Powershell variable not passed into filter - variables

I need to create scirpt which add users from list (containing user Display name) to group
Problem I encountered is :
when I issue command :
PS C:\Users\pskwarek> foreach ($a in $csv) {(get-aduser -f "DisplayName -like 'Piotr Skwarek'").samaccountname}
pskwarek
pskwarek
but if I use $a variable it doesnt work :
PS C:\Users\pskwarek> foreach ($a in $csv) {(get-aduser -f "DisplayName -like '$a.name'").samaccountname}
next step I would like to pass it to :
Add-adgroupMember -identity "groupname" -member samaccountname
but I can't make that single step
edit
PS C:\Users\pskwarek> $csv
Name
----
Piotr Skwarek
Renata Skwarek

You need to put $a.name in a subexpression:
foreach ($a in $csv)
{
$user = Get-ADUser -Filter "DisplayName -like '$($a.name)'"
Add-ADGroupMember groupname -Members $user
}

foreach ($a in $csv)
{
$sb = [scriptblock]::create("DisplayName -like '*$a*'")
(get-aduser -f $sb).SamAccountName
}

Try this:
foreach ($a in $csv) {(get-aduser -f ("DisplayName -like '{0}'" -f $a.name)).samaccountname}
You cannot use members of a variable directly in a string as you did.
Using string formatting (the '-f' syntax I proposed) always works.
Another solution would be to use a temporary variable to store $a.name

Try this:
$csv | % { Add-ADGroupMember -Identity "Groupname" -Member $_.Name }

Related

Extract values into variables from filename in Powershell

I have a Powershell script to read .sql files from a specific folder and run them against a database depending on the name of the filename.
The filenames are always the same: myDatabase.script.SomeRandomCharacters.csv
There can be many files which is why the script has a foreach loop.
[CmdletBinding()]
param (
[parameter(Mandatory = $true)][ValidateSet('dev')][String]$serverName,
[parameter(Mandatory = $true)][String]$databaseName,
)
$dir = Split-Path $MyInvocation.MyCommand.Path
$scripts = Get-ChildItem $dir | Where-Object { $_.Extension -eq ".sql" } | Where-Object { $_.Name -like "$databaseName*" }
foreach ($s in $scripts) {
$script = $s.FullName
Invoke-Sqlcmd -ServerInstance $serverName -Database $databaseName -InputFile $script
}
The issue here is that if I would have 2 databases "myDatabase" and "myDatabase2", running the script with the former input would run the latter as well since the Where-Object filtering uses an asterisk.
I can't figure out how to modify the script so that I get the absolute value of whatever is before the first fullstop in the filename. What I would also what to do is to validate the value between the first and second fullstops, in the example filename it is script.
Any help is appreciated!
Use the database names to construct a regex pattern that will match either:
param(
[Parameter(Mandatory = $true)][ValidateSet('dev')][String]$ServerName,
[Parameter(Mandatory = $true)][String[]]$DatabaseNames,
)
# Construct alternation pattern like `db1|db2|db3`
$dbNamesEscaped = #($DatabaseNames |ForEach-Object {
[regex]::Escape($_)
}) -join '|'
# Construct pattern with `^` (start-of-string anchor)
$dbNamePattern = '^{0}' -f $dbNamesEscaped
# Fetch scripts associated with either of the database names
$scripts = Get-ChildItem $dir | Where-Object { $_.Extension -eq ".sql" -and $_.Name -match $dbNamePattern }
# ...
You can use the StartsWith function to fix your filter:
$scripts = Get-ChildItem $dir | Where-Object { $_.Extension -eq ".sql" } | Where-Object { $_.Name.StartsWith("$($databaseName).") }

Invoke-AzVMRunCommand as a job

I am trying to use Invoke-AzVMRunCommand as a job. when I executed below script the job is created and executed successfully but I am failing to write the output like which job result belongs to which vm.
Invoke-AzVMRunCommand is used to invoke a command on a particular VM. You should have this information beforehand.
Here is some information on -AsJob parameter
https://learn.microsoft.com/en-us/powershell/module/az.compute/invoke-azvmruncommand?view=azps-2.6.0#parameters
As suggested by AmanGarg-MSFT, you should have that information before hand. You can use a hashtable $Jobs to store the server name and Invoke-AzVMRunCommand output and later iterate through using the $Jobs.GetEnumerator().
$Jobs = #{}
$Servers = "Server01","Server02"
[System.String]$ScriptBlock = {Get-Process}
$FileName = "RunScript.ps1"
Out-File -FilePath $FileName -InputObject $ScriptBlock -NoNewline
$Servers | ForEach-Object {
$vm = Get-AzVM -Name $_
$Jobs.Add($_,(Invoke-AzVMRunCommand -ResourceGroupName $vm.ResourceGroupName -Name $_ -CommandId 'RunPowerShellScript' -ScriptPath $FileName -AsJob))
}

Address Variables with PowerShell and Import-CSV foreach-loop

Input file:
"Server1","lanmanserver"
"Server2","lanmanserverTest"
Program
$csvFilename = "D:\Scripts\ServerMonitorConfig.csv"
$csv = Import-Csv $csvFilename -Header #("ServerName","ServiceName")
foreach ($line in $csv) {
Write-Host "ServerName=$line.ServerName ServiceName=$line.ServiceName"
}
What I want:
Server-Name=Server1 ServiceName=lanmanserver
Server-Name=Server2 ServiceName=lanmanserverT
What I'm getting:
ServerName=#{ServerName=Server1; ServiceName=lanmanserver}.ServerName
ServiceName=#{ServerName=Server1; ServiceName=lanmanserver}.ServiceN
ame ServerName=#{ServerName=Server2;
ServiceName=lanmanserverTest}.ServerName
ServiceName=#{ServerName=Server2; ServiceName=lanmanserverTest}.
ServiceName
I really don't care if the Headers come from the first row of the CSV or not, I'm flexible there.
You usually see subexpressions or format strings used to solve that:
Subexpression:
Write-Host "ServerName=$($line.ServerName) ServiceName=$($line.ServiceName)"
Format string:
Write-Host ('ServerName={0} ServiceName={1}' -f $line.ServerName,$line.ServiceName)

Read var directly from csv

Is it possible to read a variable directly by loading a csv?
My csv looks like this:
Var,Path
$SrcHost,\\computer
Is there a possibility to import-csv and put the path into the var?
import-csv test3.csv | foreach-object {
iex "$($_.var) = ""$($_.path)"""
}
You can also use new-variable (nv):
import-csv csvfile.csv | % { nv -name ($_.var) -value ($_.path) }
However to make this work you have to:
remove the $ from the source csv
or, trim $ as described by the comments below
or, select your variable as ${$srchost}
How bout this:
Get-Content -Path test.csv | Select-Object -Skip 1 | ForEach-Object { $_.Replace(",", "=`"") +
"`"" } | Invoke-Expression

How do I concatenate strings with variables in PowerShell?

I'm trying to build a file path in PowerShell and the string concatenation seems to be a little funky.
I have a list of folders:
c:\code\MyProj1
c:\code\MyProj2
I want to get the path to a DLL file here:
c:\code\MyProj1\bin\debug\MyProj1.dll
c:\code\MyProj2\bin\debug\MyProj2.dll
Here's what I'm trying to do:
$buildconfig = "Debug"
Get-ChildItem c:\code | % {
Write-Host $_.FullName + "\" + $buildconfig + "\" + $_ + ".dll"
}
This doesn't work. How can I fix it?
Try this
Get-ChildItem | % { Write-Host "$($_.FullName)\$buildConfig\$($_.Name).dll" }
In your code,
$build-Config is not a valid variable name.
$.FullName should be $_.FullName
$ should be $_.Name
You could use the PowerShell equivalent of String.Format - it's usually the easiest way to build up a string. Place {0}, {1}, etc. where you want the variables in the string, put a -f immediately after the string and then the list of variables separated by commas.
Get-ChildItem c:\code|%{'{0}\{1}\{2}.dll' -f $_.fullname,$buildconfig,$_.name}
(I've also taken the dash out of the $buildconfig variable name as I have seen that causes issues before too.)
Try the Join-Path cmdlet:
Get-ChildItem c:\code\*\bin\* -Filter *.dll | Foreach-Object {
Join-Path -Path $_.DirectoryName -ChildPath "$buildconfig\$($_.Name)"
}
This will get all dll files and filter ones that match a regex of your directory structure.
Get-ChildItem C:\code -Recurse -filter "*.dll" | where { $_.directory -match 'C:\\code\\myproj.\\bin\\debug'}
If you just want the path, not the object you can add | select fullname to the end like this:
Get-ChildItem C:\code -Recurse -filter "*.dll" | where { $_.directory -match 'C:\\code\\myproj.\\bin\\debug'} | select fullname