How to remotely rename a list of computers via PowerShell? - powershell

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
}
}

Related

Export Installed domain computer application versions to CSV - Chrome

I am attempting to export the installed version of Chrome for workstations on our network. I have put together the following script but am running into an issue with an error exporting to CSV.
Any suggestions would be greatly appreciated.
Select-Object : Cannot convert System.Diagnostics.FileVersionInfo to one of the following types {System.String, System.Management.Automation.ScriptBlock}.
At line:22 char:14
Select-Object $computer, $Version | export-csv -Path c:\ ...
CategoryInfo : InvalidArgument: (:) [Select-Object], NotSupportedException
FullyQualifiedErrorId : DictionaryKeyUnknownType,Microsoft.PowerShell.Commands.SelectObjectCommand
$computerlist = get-content C:\temp\computerlist.txt
foreach ($computer in $computerlist){
$test = 1
Write-Host "Testing connection to $computer..." -ForegroundColor Magenta
Try{
Test-Connection -Count 1 -ComputerName $computer -ErrorAction Stop | out-null
Write-Host "Connected!" -ForegroundColor Green
}
Catch{
Write-Host "Could not connect to $computer" -BackgroundColor Red -ForegroundColor Black
$test = 0
$computer | out-file c:\temp\badlist.txt
}
If ($test -eq 1){
ForEach($computer in $computerlist){
$computer = $computer
$Version = (Get-Item (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe').'(Default)').VersionInfo
"$computer - $Version"
Out-String -InputObject $Version
Select-Object $computer, $Version | export-csv -Path c:\temp\Chromeversion$($date)-PS.csv -NoTypeInformation -Append
Select-Object $computer, $Version
doesn't work as intended, because Select-Object expects property names (or calculated properties) as the (positionally implied) -Property argument.
You're passing values, which are interpreted as names, and an instance of System.Diagnostics.FileVersionInfo (the type of the value stored in $Version) isn't accepted as a name, which is what the error message indicates.
To get what you want, construct a [pscustomobject] as follows:
[pscustomobject] #{ Computer = $computer; Version = $Version } |
Export-Csv -Path c:\temp\Chromeversion$($date)-PS.csv -NoTypeInformation -Append

Rename Vm Computer name using Bulk

I have Text file with number of local VM names in Hyper-v :
newname
IL-SRV
IL-TST
IL-MGN
IL-BBT
This is the names in my hyper-V environment , And i would like to change their computer name by using Powershell and bulk
I'm using this script
$computers = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($newname in $computers){
Invoke-Command -VMName $computers.newname -Credential administrator -ScriptBlock {Rename-Computer -NewName $computers.newname -Restart -Force}
}
But i receive this error
"
Invoke-Command : The input VMName IL-SRV does not resolve to a single virtual machine.
At line:11 char:1
+ Invoke-Command -VMName $computers.newname -Credential administrator - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : InvalidVMNameNotSingle,Microsoft.PowerShell.Commands.InvokeCommandCommad
"
Each iteration you are processing the entire list of $computers.newname
In your loop you create variable $newname without ever using it. You should be very careful when running commands that make changes especially if you aren't familiar with how powershell works. The other glaring issue is you are using Invoke-Command on a remote computer but using a local variable. I am taking a guess that you're trying to do is this.
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($line in $CSVData){
Invoke-Command -VMName $line.newname -Credential administrator -ScriptBlock {Rename-Computer -NewName $using:line.newname -Restart -whatif}
}
Note the $using:line variable. This provides the contents of the local variable to the remote computer. Another way to handle it would be use the -Argumentlist. I recommend using named parameters when doing so, like this.
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($line in $CSVData){
Invoke-Command -VMName $line.newname -Credential administrator -ScriptBlock {
Param($incomingname)
Rename-Computer -NewName $incomingname -Restart -whatif
} -ArgumentList $line.newname
}
The last thing you need to do AFTER confirming it's going to do what you desire is to remove the -WhatIf parameter from Rename-Computer. Rename-Computer has a -ComputerName parameter as well, fyi.
Either of these could also be written like this since there is only one property on $CSVData that we care about
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($name in $CSVData.newname){
Invoke-Command -VMName $name-Credential administrator -ScriptBlock {Rename-Computer -NewName $using:name -Restart -whatif}
}
or
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($name in $CSVData.newname){
Invoke-Command -VMName $name -Credential administrator -ScriptBlock {
Param($incomingname)
Rename-Computer -NewName $incomingname -Restart -whatif
} -ArgumentList $name
}

Powershell Remote Stop and Disable Service

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

Powershell unregister-ScheduledTask

I'm trying to remove schedule task on remote servers.
Invoke-Command -ComputerName "name" {Unregister-ScheduledTask -TaskName $task -WhatIf}
I get the following error
Cannot validate argument on parameter 'TaskName'. The argument is null. Provide a valid value for the argument, and then try running the command again.
+ CategoryInfo : InvalidData: (:) [Unregister-ScheduledTask], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Unregister-ScheduledTask
+ PSComputerName : name
$Task='task'
If I specify the "Taskname" in text and not variable it works.
Invoke-Command -ComputerName "name" {Unregister-ScheduledTask -TaskName "task" -WhatIf}
What if: Performing operation 'Delete' on Target '\task'.
To pass a named variable to a scriptblock, do:
Invoke-Command -ComputerName $Computer -ScriptBlock {param($task) Unregister-ScheduledTask -TaskName $task } -ArgumentList $TaskName
or use the $args Automatic variable like:
Invoke-Command -ComputerName $Computer -ScriptBlock { Unregister-ScheduledTask -TaskName $args[0] } -ArgumentList $TaskName
Create the unregister file like this one I use to clear unwanted scheduled tasks:
#TaskSchdOptimizer.ps1
get-scheduledtask | where {$_.taskname -like "Optimize Start Menu Cache Files*"} | Unregister-ScheduledTask -Confirm:$false
get-scheduledtask | where {$_.taskname -like "GoogleUpdateTaskMachine*"} | Unregister-ScheduledTask -Confirm:$false
get-scheduledtask | where {$_.taskname -like "User_Feed*"} | Unregister-ScheduledTask -Confirm:$false
and then copy the file to the servers, like I do my $profile:
#Copy-UnregisterFile.ps1
$serverListFile = gc .\yourinputfolder\serverlist.txt
$file_dir="driveletter$\whereyourfileis" #DO NOT put an ending "\"!!!
#$file_name="yourunregisterfile.ps1" #<-- put yours here and remove #
$from="$file_dir\$file_name"
$dest="driveletter$\folderwhereyouwanttorunitfrom" #DO NOT put an ending "\"!!!
Foreach ($Server in $ServerListFile){
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 #<-- needed now since 2016
if ((test-path "\\$Server\driveletter$\folderwhereyouwanttorunitfrom") -ne $true){New-Item -ErrorAction Ignore -ItemType directory -Path "\\$server\driveletter$\folderwhereyouwanttorunitfrom" -Force -verbose}
Copy-Item -Path $from -Destination \\$Server\$dest\ -Force -Verbose
Write-Host " $server : copied $file_name to $dest"
}
...after that run your invoke using the file you sent...

Powershell Script reading file into array

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.