I have a script I'm working on. I want it to read in a column named ComputerName and one named UserName.
My CSV file looks like this:
ComputerName | Username
computer01 | user1
computer02 | user2
The Pipes are representing cells in excel.
Here's my script:
$computerName = #()
$userName = #()
Import-Csv C:\test\script\Computername_username_test.csv -Delimiter "|" |`
ForEach-Object
{
$computerName += $_.ComputerName
$userName += $_.UserName
}
$destination = New-Item -ItemType Directory -Path C:\test\$userName\dictionary_Files\ -force
$fileList = Get-WmiObject -Class CIM_DataFile -Filter "Drive='C:' And Extension='dic'" -Computername $computerName
foreach ($file in $fileList)
{
$drive, $path = $file.Name.Split('\',2)
$drive = $drive -replace ':','$'
$remoteFile = "\\$computerName\$drive\$path"
Write-Verbose "Copy $remoteFile to $destination"
Copy-Item $remoteFile -Destination $destination -Confirm
}
My goal is to search the C drive of the remote computer for all files with the .dic extension and copy them to a location inside a folder that is named the same as their username from the excel sheet.
When I run this I'm getting the following:
PS C:\Test\Script> C:\Test\Script\DicFiles03_importCSV.ps1
cmdlet ForEach-Object at command pipeline position 2
Supply values for the following parameters:
Process[0]:
$computerName += $_.ComputerName
$userName += $_.UserName
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'. The argument is null, empty, or an element of the argument
collection contains a null value. Supply a collection that does not contain any null values and then try the command again.
At C:\Test\Script\DicFiles03_importCSV.ps1:13 char:102
+ ... -Filter "Drive='C:' And Extension='dic'" -Computername $computerName
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Thank you for your help.
I'm think its because you have your { after the foreach-object on the next line powershell is a scripting language so its particular about line endings.
Related
I'm trying to access the service status of the remote server. i wrote this
$ServerList = get-content -Path "c:\users\cont015\Desktop\ServerList.txt"
ForEach ($ServerName in $ServerList)
{
$Status= Get-Service -ComputerName $ServerName | ?{$_.DisplayName -like "SQL Server (*"} | select Status | format-wide
if($st -eq "Running")
{
$SeverName
$Status
}
else
{
}
}
it is showing
$Status= Get-Service -ComputerName $ServerName | ?{$_.DisplayName -li ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Service], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetServiceCommand
in error. i don't know what i am missing. but when i run without if condition if shows proper output.
$ServerList = Get-Content -Path "c:\users\cont015\Desktop\ServerList.txt"
ForEach ($ServerName in $ServerList)
{
$Status= #(
Get-Service -ComputerName $ServerName -DisplayName "SQL Server (*" |
Select-Object -ExpandProperty Status)
if ("Running" -in $Status)
{
[PSCustomObject]#{
Server = $ServerName
Status = $Status
}
}
else
{
}
}
Explanation:
Get-Service docs: -DisplayName
Specifies, as a string array, the display names of services to be retrieved. Wildcards are permitted (used instead of Where-Object as such filtering is always faster).
Array subexpression operator #( ). -
Returns the result of one or more statements as an array. The result is always an array of 0 or more objects (i.e. force Powershell to always return an array when a call returns only one object or even $null)
Used [PSCustomObject]#{} in output instead of a sequence of strings (learn advantages at Everything you wanted to know about PSCustomObject).
I am having the below code to get the data from remote servers. thanks to #Santiago Squarzon
$serverlist = Get-Content -Path "C:\ServerList.txt"
# Collect results here
$result = Invoke-Command -ComputerName $serverlist -ScriptBlock {
$paths_list = $env:Path -Split [System.IO.Path]::PathSeparator
foreach($sys_Path in $paths_list)
{
$Permissions = (Get-Acl -Path $sys_Path).Access
foreach($acl in $Permissions)
{
if(-not $acl.IdentityReference)
{
continue
}
[pscustomobject]#{
ComputerName = $env:ComputerName
SystemFolderPath = $sys_Path
IdenityReference = $acl.IdentityReference.Value
FileSystemRights = $acl.FileSystemRights
}
}
}
} -HideComputerName
$result | Export-Csv -Path "C:\status_report.csv" -NoTypeInformation
But I am getting below error while executing it
Cannot validate argument on parameter 'Path'. The argument is null or empty. Provide an argument that is not null or
empty, and then try the command again.
+ CategoryInfo : InvalidData: (:) [Get-Acl], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetAclCommand
+ PSComputerName
Please let me know on this.
Might adding the following check before $Permissions = (Get-Acl -Path $sys_Path).Access would resolve the issue:
if (($sys_Path -eq $null) -or ($sys_Path -eq '') ) {
continue
}
SO Braintrust. I'm not a Powershell person, but I'm working on it. Trying to address yet another zero-day, I'm trying to build a reuseable script to remotely stop and disable the affected service. It is based on a script I got from a Microsoft MVP at (ultimately): http://portal.sivarajan.com/2010/07/stopstart-or-enabledisable-service_26.html
The prompt for the service name was added by me as well as the output information (Write-host & Add-Content lines), so I could get a results summation (the output part's not working fully, but it's the least of my concerns at the moment.).
$output = "c:\scripts\results.csv"
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output Start"
cls
$Cred = Get-Credential
$service = Read-Host -Prompt 'Enter Service Name" '
Import-CSV C:\Scripts\computers.csv | %
{
$computer = $_.ComputerName
Write-Host "Working on $computer"
Add-content -path $output "$computer"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).stopservice()
Add-content -path $output " Stop - $result"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).ChangeStartMode("Disabled")
Add-content -path $output " Disable - $result"
}
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output End"
when I run it, I get an error on the computer name
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'.
The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Scripts\StopAndDisableService.ps1:12 char:54
+ ... result = (Get-WmiObject win32_service -computername $computer -filter ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Scripts\StopAndDisableService.ps1:14 char:54
+ ... result = (Get-WmiObject win32_service -computername $computer -filter ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Computer.csv contains one computer name per line, no punctuation, no FQDN, just the computer name
Special thanks to #Mathias R. Jessen for his help on this. Final working code. you will have to analyze the screen output to catch any errors and see which machines it did not catch due to being offline # time of running (some output file items have been commented out since they don't work as intended)
$output = "c:\scripts\results.csv"
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output Start"
cls
$Cred = Get-Credential
$service = Read-Host -Prompt 'Enter Service Name" '
Import-CSV C:\Scripts\computers.csv -Header ComputerName | % {
$computer = $_.ComputerName
Write-Host "Working on $computer"
Add-content -path $output "$computer"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).stopservice()
#Add-content -path $output " Stop - $result"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).ChangeStartMode("Disabled")
#Add-content -path $output " Disable - $result"
}
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output End"
Analyzing results on the screen output, any results with
Just the machine name - means it's processed without error on that machine (success)
RPC server is unavailable means machine is offline
Cannot call a method on Null-Valued expression on line 12 or line 14 means that service doesn't exist on that machine
The results.csv output file will contain list of names of the machines this script was run against
I'm on a Windows server 2008 R2 and I need an extract of the local profile list, so I use Powershell to look into the registry and get what I want :
$path = 'Registry::HKey_Local_Machine\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\*'
$items = Get-ItemProperty -path $path
Foreach ($item in $items) {
$objUser = New-Object
System.Security.Principal.SecurityIdentifier($item.PSChildName)
$objName = $objUser.Translate([System.Security.Principal.NTAccount])
$item.PSChildName = $objName.value
}
echo $items | Select-Object -Property PSChildName | Export-Csv
C:\scripts\PSScripts\UserProfile.csv -Encoding UTF8
It worked with another machine using Windows Server 2012 R2 but here I got a lot of errors, but always the same one :
Exception calling "Translate" with "1" argument(s): "Some or all
identity references could not be translated." At
C:\scripts\PSScripts\users_profile.ps1:5 char:34
+ $objName = $objUser.Translate <<<< ([System.Security.Principal.NTAccount])
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
The .csv file is created but with issues, like a profile shown more than one time, like this :
DOMAIN\User1
DOMAIN\User2
DOMAIN\User3
DOMAIN\User3
DOMAIN\User4
DOMAIN\User5
DOMAIN\User5
DOMAIN\User5
DOMAIN\User6
Is there a difference between WS2008 and WS2012 which can cause this problem? Or is it something else?
I'd suggest using WMI to be consistent across platforms plus some error handling:
$path = 'C:\scripts\PSScripts\UserProfile.csv'
Get-CimInstance -ClassName Win32_UserProfile -Filter Special=FALSE -PipelineVariable user |
ForEach-Object -Begin {$ErrorActionPreference = 'Stop'} {
try
{
$id = [System.Security.Principal.SecurityIdentifier]::new($user.SID)
$id.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
Write-Warning -Message "Failed to translate $($user.SID)! $PSItem"
}
} |
Select-Object -Property #{Label='PSChildName'; Expression={$PSItem}} |
Export-Csv -Path $path -Encoding ascii -NoTypeInformation
PSv2 solution:
Get-WmiObject -Class Win32_UserProfile -Filter Special=FALSE |
ForEach-Object -Begin {$ErrorActionPreference = 'Stop'} {
try
{
$sid = $_.SID
$id = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $sid
$id.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
Write-Host "Failed to translate $sid! $_" -ForegroundColor Red
}
} |
Select-Object -Property #{Label='PSChildName'; Expression={$_}} |
Export-Csv -Path $path -Encoding ascii -NoTypeInformation
I have a largish set of Windows 10 workstations that need to be renamed. I've tried running the script below, but get errors that are beyond my current PS level.
$computers = Import-Csv "c:\rename-computers\computers.csv"
foreach ($oldname in $computers){
#Write-Host "EmpID=" + $computers.NewName
Rename-Computer -ComputerName $computers.OldName -NewName $computers.NewName -DomainCredential hole\inwall -Force -Restart
}
Produces:
Rename-Computer : Cannot convert 'System.Object[]' to the type
'System.String' required by parameter 'ComputerName'. Specified
method is not supported. At
\siat-ds0\appdeploy\LabPacks\rename-computers\rename-siat.ps1:4
char:35
+ Rename-Computer -ComputerName $computers.OldName -NewName $computers.NewName ...
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Computer], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.RenameComputerCommand
I've seen similar closed threads on this topic elsewhere without mention of the error I'm receiving.
You mistakenly used the collection variable $computers instead of the loop-iteration variable $oldname inside your loop, and since $computers.NewName expanded to an array of names rather than a single one, you got the error you saw.
That said, you don't need a loop at all - a single pipeline will do:
Import-Csv "c:\rename-computers\computers.csv" |
Rename-Computer -ComputerName { $_.OldName } -DomainCredential hole\inwall -Force -Restart
Rename-Computer will implicitly bind the NewName property of each input object to the -NewName parameter.
The -ComputerName parameter, by contrast, must be told what property on the input objects to access, given that the input objects have no ComputerName property.
This is what script block { $_.OldName } does, inside which automatic variable $_ represents the input object at hand.
To see which parameters accept pipeline input, examine the output from
Get-Help -full Rename-Computer; for details and a programmatic alternative, see this answer of mine.
You are iterating but not using the singular:
Instead of this:
foreach ($oldname in $computers){
#Write-Host "EmpID=" + $computers.NewName
Rename-Computer -ComputerName $computers.OldName -NewName $computers.NewName -DomainCredential hole\inwall -Force -Restart
}
Try this:
foreach ($oldname in $computers){
Rename-Computer -ComputerName $oldname.OldName -NewName $oldname.NewName -DomainCredential hole\inwall -Force -Restart
}
Note: $oldname is holding one value at a point. So the number of computers present in $computers will come one by one to $oldname and will perform the activity inside the loop.
You should use the singular $oldname inside the loop to iterate one by one.
Bulk rename computers in AD
Powershell bulk rename computers in AD with test if pc is online and if new name is already taken and log "not-renamed" PC.
adc.csv
oldname,newname
WEDSKS0022,RKVKS0110
WEDSKS0117,RKVKS1413
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force;
$computers = import-csv -Path ".\adc.csv"
$Credential = Get-Credential
$nisuprosli=".\notrenamed $(get-date -f dd-MM-yyyy-HHMM).csv"
$makecsv="oldname,newname" | Out-File $nisuprosli -Encoding utf8 -Append
foreach ($pc in $computers){
$IsOldPCalive=Test-Connection -ComputerName $pc.oldname -Quiet -Count 1 -ErrorAction SilentlyContinue
$IsNewPCalive=Test-Connection -ComputerName $pc.newname -Quiet -Count 1 -ErrorAction SilentlyContinue
if ($IsOldPCalive -eq $True -and $IsNewPCalive -eq $False) {
write-host "Rename PC $($pc.oldname) u $($pc.newname)" -ForegroundColor Cyan
Rename-computer -computername $pc.oldname -newname $pc.newname -domaincredential $Credential -PassThru -force -restart #-WhatIf
}
else {
write-host "PC $($pc.oldname) is not available or already exists $($pc.newname)" -ForegroundColor Yellow
$makecsv="$($pc.oldname),$($pc.newname)" | Out-File $nisuprosli -Encoding utf8 -Append
}
}