This example is easy enough:
PS C:\Users\saunders\Desktop\misc>
PS C:\Users\saunders\Desktop\misc> $hash = #"
>> Name = Jackson
>> Employer = BigData
>> EmpID = 2032
>> Type = Permanent
>> "#
PS C:\Users\saunders\Desktop\misc>
PS C:\Users\saunders\Desktop\misc> $hash
Name = Jackson
Employer = BigData
EmpID = 2032
Type = Permanent
PS C:\Users\saunders\Desktop\misc>
PS C:\Users\saunders\Desktop\misc> $hash | ConvertFrom-StringData
Name Value
---- -----
Employer BigData
Type Permanent
EmpID 2032
Name Jackson
PS C:\Users\saunders\Desktop\misc>
Which is excellent and the desired output. Here:
PS C:\Users\saunders\Desktop\misc>
PS C:\Users\saunders\Desktop\misc> cat .\hash.txt
$hash = #"
Name = Jackson
Employer = BigData
EmpID = 2032
Type = Permanent
"#
PS C:\Users\saunders\Desktop\misc>
PS C:\Users\saunders\Desktop\misc> $foo = Get-Content .\hash.txt
PS C:\Users\saunders\Desktop\misc>
PS C:\Users\saunders\Desktop\misc> $foo
$hash = #"
Name = Jackson
Employer = BigData
EmpID = 2032
Type = Permanent
"#
PS C:\Users\saunders\Desktop\misc>
the data originates in a file. How is this file read as a here-string so that it can be used as above?
Your .\hash.txt is in effect a .ps1 script file, so you could change its extension an then load it via ., the dot-sourcing operator, at which point $hash will be defined and can be passed to ConvertFrom-StringData.
To process the file as-is, you can pass its content to Invoke-Expression (though note that this cmdlet should generally be avoided):
Invoke-Expression (Get-Content -Raw t.txt)
$hash | ConvertFrom-StringData
If you have control over how .\hash.txt gets created and can change its name, you can save it as a PowerShell data file, i.e. with extension .psd1, which can be read as-is with the Import-PowerShellDataFile cmdlet:
A .psd1 file is in effect the source-code representation of a hashtable literal, whose syntax requirements are more stringent than for text that can be parsed with ConvertFrom-StringData:
# Save the source-code representation of a hashtable literal
# to a file - do NOT include a variable assignment:
#'
#{
Name = 'Jackson'
Employer = 'BigData'
EmpID = 2032
Type = 'Permanent'
}
'# > hash.psd1
Import-PowerShellDataFile hash.psd1
As an aside:
As of PowerShell 7.3.2, both ConvertFrom-StringData and Import-PowerShellData do not preserve the entries in definition order, given that [hasthable] instances are inherently unordered.
GitHub issue #19070 proposes overcoming this limitation, by making these cmdlets return ordered hashtables instead, via System.Management.Automation.OrderedHashtable, which derives from [hashtable].
Related
This question already has answers here:
How can you use an object's property in a double-quoted string?
(5 answers)
Closed 5 months ago.
I wrote a script that allows me to query the whole Azure database park:
#$ErrorActionPreference = 'SilentlyContinue'
# Connect to Azure
$azureAccount = Connect-AzAccount
# Get Azure Access Token (we will use this to query the databasees)
#$azureToken = Get-AzAccessToken -ResourceUrl https://database.windows.net
$access_token = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
# Queries will be picked up from here
$folderPath = '.\Queries'
# Choose how to format each date ("yyyy-MM-dd") or ("yyyy-MM-dd HH:mm:ss")
$DateTime = (Get-Date).ToString("yyyy-MM-dd")
# List Azure Sunscriptions
Get-Azsubscription | ForEach-Object -Begin { $a = 1 } -Process {"$a $($_.Name)"; $a++}
$SubscriptionChoice = Read-Host -Prompt "Copy/paste the name of the Subscription that you want to investigate. If more than one separate them by a coma, Type `"All`" if you want to target all of them"
# Iterate into subscriptoins and print names
foreach ($gs in $SubscriptionChoice) {
Select-Azsubscription -Subscription "$gs" | Out-Null
Write-Host "Let's browse into Azure Sunscription: " -NoNewline
Write-Host (Get-AzContext).Subscription.Name -ForegroundColor green
# Fins all Azure SQL Server
Get-AzSqlServer | ForEach-Object -Begin { $a = 1 } -Process {"$a $($_.ServerName)"; $a++}
$SqlServerChoice = Read-Host -Prompt "Copy/paste the name of the SQL Server that you want to investigate. If more than one separate them by a coma, Type `"All`" if you want to target all of them"
if ($SqlServerChoice = "All"){
$SqlServerChoice = Get-AzSqlServer
}
Foreach ($server in $SqlServerChoice){
$DatabaseChoice = Get-AzSqlDatabase -ServerName $server.ServerName -ResourceGroupName $server.ResourceGroupName | Where-Object DatabaseName -NE "master"
Foreach ($database in $DatabaseChoice){
(Get-ChildItem $folderPath | sort-object {if (($i = $_.BaseName -as [int])) {$i} else {$_}} ).Foreach{
Invoke-Sqlcmd -ServerInstance $server.FullyQualifiedDomainName -Database $database.DatabaseName -AccessToken $access_token -InputFile $psitem.FullName | Export-Csv -Path ".\Results\$psitem.csv" -Append -NoTypeInformation
write-host "Executing $psitem on $database.DatabaseName"
}
}
}
}
However each time the query is executed against a database the Write-Hosts returns:
Executing DTU_to_vCore.sql on Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel.DatabaseName
Here a picture:
This Write-Hosts comes from the line:
write-host "Executing $psitem on $database.DatabaseName"
In which you can find the two variables:
$psitem : which is the name of the file that contains the query
$database.DatabaseName : which should be the database name but instead of printing the database name is printing Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel.DatabaseName
Why one of the two variable is not interpreted?
You need to encapsulate your variable property in a subexpression operator $().
write-host "Executing $psitem on $($database.DatabaseName)"
This is because only simple variables get expanded in an expandable string.
References
Only simple variable references can be directly embedded in an
expandable string. Variables references using array indexing or member
access must be enclosed in a subexpression.
Source: about_Quoting_Rules
Subexpression operator $( )
Returns the result of one or more statements. For a single result,
returns a scalar. For multiple results, returns an array. Use this
when you want to use an expression within another expression. For
example, to embed the results of command in a string expression.
PS> "Today is $(Get-Date)"
Today is 12/02/2019 13:15:20
PS> "Folder list: $((dir c:\ -dir).Name -join ', ')"
Folder list: Program Files, Program Files (x86), Users, Windows
Source: about_Operators
Trying to take an object and filter down to a value as a string. And save that string to variable and then use that variable in another command as a value for a flag.
So this command will get the PNPDevice InstanceID
$x = (Get-PnpDevice -PresentOnly -Class 'Net' | Where-Object {$_.FriendlyName -EQ 'Intel(R) Ethernet Connection I217-LM'} | Select-Object -ExpandProperty InstanceId | Format-Table -AutoSize | out-string )
Here I am checking the variable X and its content and type since the next command Disable-PNPDevice and the flag instanceID has to be a string
PS C:\Temp> $x.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
PS C:\Temp> echo $x
PCI\VEN_1234&DEV_543A&SUBSYS_32A39857&REV_04\3&1234839&0&C8
When I try to use $x for -InstanceId i get this error
PS C:\Temp> Disable-PnpDevice -InstanceId $x
Disable-PnpDevice : Invalid query
At line:1 char:1
+ Disable-PnpDevice -InstanceId $x
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (Win32_PnPEntity:ROOT\cimv2\Win32_PnPEntity) [Disable-PnpDevice], CimException
+ FullyQualifiedErrorId : HRESULT 0x80041017,Disable-PnpDevice
However if I manually create the variable with a string it works fine
PS C:\Temp> $y = "PCI\VEN_1234&DEV_543A&SUBSYS_32A39857&REV_04\3&1234839&0&C8"
PS C:\Temp> Disable-PnpDevice -InstanceId $y
PS C:\Temp> $y.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
Thank you.
Omit | Format-Table -AutoSize | out-string from your command, which is not only redundant in your case (the .InstanceId property already is a string), but causes the instance ID string to have a trailing newline, which is likely the cause of your problem.
Generally:
Format-* cmdlets emit output objects whose sole purpose is to provide formatting instructions to PowerShell's for-display output-formatting system. In short: only ever use Format-* cmdlets to format data for display, never for subsequent programmatic processing - see this answer for more information.
As an aside: That Out-String blindly appends a trailing newline to its output string is both unexpected and inconvenient: see GitHub issue #14444.
Note: With a single input object (such as in your case), -NoNewLine can be used to suppress the trailing newline (but Out-String is never needed for an input object that already is a string).
The problem is that with multiple input objects, -NoNewLine also suppresses newlines between their representations; e.g., 'one', 2 | Out-String -NoNewLine yields verbatim one2
Any ideas how to get the file hash of a OneDrive (SP) file? I really can't stand SP would be nice to do with PnP
$res = (Get-PnPFile -URL "/Documents/Au-Crouchy.xlsx").OpenBinaryStream()
Invoke-PnPQuery
$stream = Add-PnpFile -FileName $a -Folder "TargetLib" -Stream $res.Value
Get-FileHash -InputStream $stream | select-object hash
I tried other options for getting the file hash. Error received is:
Get-FileHash : Cannot process argument transformation on parameter 'InputStream'. Cannot convert the "Microsoft.SharePoint.Client.File" value of type "Microsoft.SharePoint.Client.File" to type "System.IO.Stream".
Thanks
I need to extract a variable on a single line in a txt file like so;
Write-Host "Select RDS Collection to migrate"
$AllCollections.Keys | Sort-Object | ForEach-Object { Write-Verbose "[$_] - $($AllCollections.$_)" -Verbose }
Write-Output ''
$Collection = $AllCollections.$((Read-Host -Prompt 'Choose collection number') -as [int])
$oldrdscb = "RDSCB01N01"
$newrdscb = "RDSCB02N01"
$newrdscbsmb = "\\$newrdscb\C$\temp\migrationvariables.txt"
echo "$collection" = "$Collection" | Out-File -FilePath $newrdscbsmb -append -width 200
txt file \RDSCB02N01\c$\temp\migrationvariables.txt now containts:
RDS-FSLOGIXTEST
=
RDS-FSLOGIXTEST
this because it reads the first $collection and the gives the output of $collection variable, which makes sense.
How can i get the result without the variable of the first $collection and send it as text instead of a variable so the end result in the txt would be:
$collection = TEST
The txt is emtpy before running this code.
The Goal here is to read the variables on my new rds server to migrate theme.
Any tips? thank you!
You just need to escape the dollar signs using the backtick (`). It is usually above the tab key on the keyboard.
$oldrdscb = "RDSCB01N01"
$newrdscb = "RDSCB02N01"
$newrdscbsmb = "\\$newrdscb\C$\temp\migrationvariables.txt"
echo "`$collectioname" = "`$Collection" | Out-File -FilePath $newrdscbsmb -append -width 200
I have a list of variables:
$desa = "filtering regex for desa"
$cdo = "different regex for cdo"
etc.
Now, I have a loop:
Foreach ($profilename in ("desa", "cdo")) {
# filter out data from $profilename file where regex is contained in
# variable named after the content of $profilename
}
So, in other words, I need to use a string contained in one of the variables at the top, and the name of that variable is the exact content of the $profilename variable.
Can PowerShell do this?
Might be easier to us a hash table of regexes than separate variables for each one:
$filters = #{
desa = "filtering regex for desa"
cdo = "different regex for cdo"
}
Foreach ($profilename in
( "desa", "cdo")
)
{
(Get-content <profilename file>) -match $filters[$profilename]
}
Just name the keys after your profile names.
As #mjolinor said: hashtables are a better approach for this. However, if for some reason you must expand a "constructed" variable you can do it by using the $ExecutionContext automatic variable:
PS C:\> $a = 'foo'
PS C:\> $b = 'a'
PS C:\> $c = "`$$b"
PS C:\> $c
$a
PS C:\> $ExecutionContext.InvokeCommand.ExpandString($c)
foo
Applied to your code that might look like this:
$desa = "filtering regex for desa"
$cdo = "different regex for cdo"
foreach ($profilename in 'desa','cdo') {
$pattern = $ExecutionContext.InvokeCommand.ExpandString("`$$profilename")
$something | ? { $_ -match $pattern } | ...
}