Powershell: Re-Install Printer depending on Username - powershell

I'm trying to learn Powershell and have no experience in any script language at all (well, except Batch a bit).
What I'm trying to do is to run this Batch command -> IF "%USERNAME%"=="Admin" GOTO Admin as a Powershell command and afterwards reinstall the users Default printer. The reason why I Need a goto is because I want to use the same script for several Users. This is what I have so far as a Batch/Powershell Hybrid
IF "%USERNAME%"=="Admin" GOTO Admin
:Admin
powershell
(New-Object -ComObject WScript.Network).RemovePrinterConnection("\\Server\adprinter")
(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\Server\adprinter")
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where ShareName = 'adprinter'"
$printer.SetDefaultPrinter()
exit
GOTO eof
I'd like to do the whole Thing in powershell but I just don't get it. I read that you can do a "goto" in powershell with a if-loop. for example that's what I have
$user = [Environment]::UserName
if ($user = Admin) do {""}
But how do I run my commands now? and how do I do another Loop for other usernames?
Thank you for your help!
EDIT:
Here is the whole script I have so far. I Need a "goto" because I have more than one User, and each of them Needs his own Printer. It would be nice to transform every Batch command into a powershell command.
#echo off
IF "%USERNAME%"=="user1" GOTO user1
IF "%USERNAME%"=="user2" GOTO user2
IF "%USERNAME%"=="user3" GOTO user3
IF "%USERNAME%"=="user4" GOTO user4
IF "%USERNAME%"=="user5" GOTO user5
:user1
powershell
(New-Object -ComObject WScript.Network).RemovePrinterConnection("\\Server\printer1")
(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\Server\printer1")
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where ShareName = 'printer1'"
$printer.SetDefaultPrinter()
exit
GOTO eof
:user2
powershell
(New-Object -ComObject WScript.Network).RemovePrinterConnection("\\Server\printer2")
(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\Server\printer2")
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where ShareName = 'printer2'"
$printer.SetDefaultPrinter()
exit
GOTO eof
:user3
powershell
(New-Object -ComObject WScript.Network).RemovePrinterConnection("\\Server\printer3")
(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\Server\printer3")
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where ShareName = 'printer3'"
$printer.SetDefaultPrinter()
exit
GOTO eof
:user4
powershell
(New-Object -ComObject WScript.Network).RemovePrinterConnection("\\Server\printer4")
(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\Server\printer4")
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where ShareName = 'printer4'"
$printer.SetDefaultPrinter()
exit
GOTO eof
:user5
powershell
(New-Object -ComObject WScript.Network).RemovePrinterConnection("\\Server\printer5")
(New-Object -ComObject WScript.Network).AddWindowsPrinterConnection("\\Server\printer5")
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where ShareName = 'printer5'"
$printer.SetDefaultPrinter()
exit
GOTO eof
:eof
exit

I agree with arco I like the use of HashTables and your issue is perfect for it. Take a look at my code here it should give you a good point for a Powershell Start.
$drac = #{ }
Import-Csv \\RemoteServer\Share\Folder\Powershell-scripts\Connect-rac.CSV | ForEach-Object {
$drac[$_.ServerName] = $_.IMM
}
If you look at the above this is what takes my CSV file and loads it into the hashtable
and below if how my code is used, I make it look for the computer name and if the matches then it will return the hashtable value.
if ($drac.Contains($ComputerName))
{
Write-Host "Servername : $ComputerName"
$URL = $drac[$ComputerName]
$IE = New-Object -COM 'InternetExplorer.Application'
$IE.Navigate2("http:\\$URL")
$IE.Visible = $true
}
See if this helps you.

Related

How to run Command as a different user with Powershell?

I'm trying to make a script that changes the HostnameAlias for a given dns record.
But only certain users have access to editing these records, for example ADMIN can edit it but CURRENTUSER cannot.
Currently I have this piece of code:
param(
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
$Credential = $(Get-Credential)
)
$Command = "Set-DnsServerResourceRecord -NewInputObject $($NewObject) -OldInputObject $($OldObject) -ZoneName $($ZoneName)"
Start-Process -FilePath PowerShell -NoNewWindow -Credential $Credential -ArgumentList $Command
But i just keep getting Start-Process : This command cannot be run due to the error: The user name or password is incorrect even though I am absolutely sure they are indeed correct.
What am I doing wrong here.
Ps, I have looked at all the related questions, none seem to answer my question.
You can call System.Management.Automation.PSCredential object to specify any credentials you want and run with it in any process
$User = 'yourdomain\youruser'
$Password = 'yourpassword'
$Secure_Password = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($User, $Secure_Password)
$Command = "Set-DnsServerResourceRecord -NewInputObject $($NewObject) -OldInputObject $($OldObject) -ZoneName $($ZoneName)"
Start-Process -FilePath PowerShell -NoNewWindow -Credential $Credential -ArgumentList $Command
You can use this:
#Get User credential
$Credential = Get-Credential Domain\UserNameYouWant
#Use System.Diagnostics to start the process as User
$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
#With FileName we're basically telling powershell to run another powershell process
$ProcessInfo.FileName = "powershell.exe"
#CreateNoWindow helps avoiding a second window to appear whilst the process runs
$ProcessInfo.CreateNoWindow = $true
#Note the line below contains the Working Directory where the script will start from
$ProcessInfo.WorkingDirectory = $env:windir
$ProcessInfo.RedirectStandardError = $true
$ProcessInfo.RedirectStandardOutput = $true
$ProcessInfo.UseShellExecute = $false
#The line below is basically the command you want to run and it's passed as text, as an argument
$ProcessInfo.Arguments = "The command you want"
#The next 3 lines are the credential for User as you can see, we can't just pass $Credential
$ProcessInfo.Username = $Credential.GetNetworkCredential().username
$ProcessInfo.Domain = $Credential.GetNetworkCredential().Domain
$ProcessInfo.Password = $Credential.Password
#Finally start the process and wait for it to finish
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessInfo
$Process.Start() | Out-Null
$Process.WaitForExit()
#Grab the output
$GetProcessResult = $Process.StandardOutput.ReadToEnd()
# Print the Job results
$GetProcessResult
Just a mistake on my part, forgot to specify domain before username when entering credentials.
Can solve it like this Get-Credential Domain\

Powershell Set default printer when the installation is done

I have exported my network printers to an .xml file so they can be installed on a new PC.
Also, I haveexportet the default printer to a file so you can set a default printer after the installation.
The installation works fine. The problem is that the installation of the printers has not been completed before the script try to set the default printer.
This is my script to install the printers:
#Install the printer
$PrinterList = Import-Clixml H:\Backup\printers_export.xml
foreach($Printer in $PrinterList) {
Invoke-Expression 'rundll32 printui.dll PrintUIEntry /in /q /n $($Printer.Name)'
}
# Set default printer
(New-Object -ComObject WScript.Network).SetDefaultPrinter((get-content h:\Backup\DefaultPrinter.txt))
One solution I have found is to put a Start-Sleep -s 15 after the first calls, can anyone point me to a better solution?
Add do/while loop condition to wait for default printer configuration is done. Like so:
$DP = (New-Object -ComObject WScript.Network).SetDefaultPrinter((Get-Content H:\Backup\DefaultPrinter.txt))
do {
Start-Sleep -Seconds 1
[wmi]$wmi = Get-WmiObject -Query " SELECT * FROM Win32_Printer" |
Where { $_.Name -eq 'PUT YOUR DEFAULT PRINTER NAME HERE' -and $_.Default -eq $true}
}while(-not$wmi)
This is the script right now:
Restore printer
$PrinterList = Import-Clixml H:\Backup\printers_export.xml
FOREACH ($Printer in $PrinterList) {
Invoke-Expression 'rundll32 printui.dll PrintUIEntry /in /q /n $($Printer.Name)'
}
RUNDLL32.EXE user32.dll,UpdatePerUserSystemParameters
Set Default printer
$DP = (New-Object -ComObject WScript.Network).SetDefaultPrinter((Get-Content H:\Backup\DefaultPrinter.txt))
do {
Start-Sleep -Seconds 1
[wmi]$wmi = Get-WmiObject -Query " SELECT * FROM Win32_Printer" |
Where { $.Name -eq '$DP' -and $.Default -eq $true}
}while(-not$wmi)
It does not work.
Can not find the default printer and the script keeps running.

Run code as different user to have elevated privileges

I'm deploying a monitoring system, and even though it has a large number of plugins, some need to run as a different user to run right.
So I switched to powershell, but the problem is the same, I have some code that give me access denied, because the user has no elevated privileges.
My question how can I run this code as different user, I tried this
$usuario = "myuser#mydomain"
$pass = get-content C:\credential.txt`
$spass = $pass | Convertto-SecureString`
pass = "securepass"`
spass = $pass | ConvertTo-SecureString -AsPlainText -Force`
write-host $pass
$cred = new-object System.Management.Automation.PSCredential -argumentlist $usuario, $spass
$UpdateSession = New-Object -ComObject Microsoft.Update.Session
$UpdateSearcher = ($UpdateSession.CreateupdateSearcher())
$Updates = $UpdateSearcher.Search("IsAssigned=1 and IsHidden=0 and IsInstalled=0").updates
$total = $Updates | measure
$total.count
Then how can I pass the credentials to the variables. The problem access denied come from this line
$Updates = $UpdateSearcher.Search("IsAssigned=1 and IsHidden=0").updates
$args = ' -file path-to-script.ps1'
Start-Process -FilePath powershell.exe -Credential $creds -ArgumentList $args -Verb RunAs
Powershell also has -Command which you can use to call a function or cmdlet instead of another script.

How to log into remote servers?

I currently have a VBScript that reads a list of servers, and attempts to verify the password of a specific userid. The userid is locally on that server. I am checking to see that the password is not set to the default (I want to make sure it was changed to something else).
The "list of servers" can be a mix of IP addresses, hostnames (like Rocky), or fully qualified DNS names (like rocky.bigcompany.com). The servers are a mixture of physical and virtual devices, and may or may not be on a domain.
The existing VBScript I wrote handles all this, and works fine. I'm trying to re-write this same program in Powershell, and It's not working.
Here's the function I have in VBScript that does what I want:
Function LoginToServer(Computer, username, password)
'this function will log into a server
On Error Resume next
Set locator = CreateObject("WbemScripting.SWbemLocator")
Set wmi = locator.ConnectServer(computer, "root\cimv2", username, password)
'check the error code and see if we logged in successfully
LoginRC = Err.Number
If LoginRC <> 0 Then
msg = "Could not log into server: " & CStr(computer) & " With ID: " & CStr(username)
lfo.lmsg "B", "WARN", msg
Else
msg = "Server: " & CStr(computer) & " Logged in successfully as: " & CStr(username)
lfo.lmsg "B", "INFO", msg
End If
wmi.Security_.ImpersonationLevel = 3
'return the code back to calleer
LoginToServer = LoginRC
End Function
… and here's what I've tried to do in PowerShell:
Param($ComputerName = "LocalHost")
$ErrorActionPreference = "Stop"
# Actual Code starts here
Write-Host "Attempting to ping server: $ComputerName"
$IPResult = Test-Connection -ComputerName $ComputerName -Quiet
if ($IPResult -eq "TRUE") {
Write-Host "Ping OK - now attempting to log in"
try {
$ID = "userid"
$PSW = "password"
$password = ConvertTo-SecureString $PSW -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ($ID, $password)
$sesh = New-PSSession -ComputerName $ComputerName -Credential $cred
} catch {
Write-Host "Error caught"
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
} finally {
$Time = Get-Date
"$Time Computer: $ComputerName ERROR: $ErrorMessage ITEM: $FailedItem" |
Out-File c:\temp\TestCredScript.log -Append
}
} else {
Write-Host "Could not ping server"
}
How do I log into these remote computers with an ID and Password using PowerShell?
Your two code samples do different things. The VBScript code connects via WMI whereas the PowerShell code tries to establish a PowerShell session. For the latter you need PowerShell Remoting enabled, which you probably don't have.
While you probably may want to enable PSRemoting anyway, you can also use WMI from PowerShell. The Get-WmiObject cmdlet allows you to provide credentials and impersonation level, so you don't need to establish a connection first like you need to do with VBScript (if you want to use explicit credentials).
Example querying the Win32_Process class on a remote computer:
$computer = '...'
$username = 'userid'
$password = 'password'
$pw = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ($username, $pw)
Get-WmiObject -Computer $computer -Namespace 'root\cimv2' -Class Win32_Process -Impersonation 3 -Credential $cred
See here for further information.

rdesktop shell escaping issue

I'm trying to send this:
Get-WmiObject Win32_PNPEntity |Where{$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}
over rdesktop like:
rdesktop -a8 209.** -u ** -p ** -s "cmd.exe /K powershell.exe Get-WmiObject Win32_PNPEntity |Where{\$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}"
But windows' shell says:
'Where{$_.DeviceID.StartsWith' is not recognized as an internal or externa....
What am I doing wrong?
why not using powershell wmi remoting?
$cred = get-credential
Get-WmiObject Win32_PNPEntity -computerName MyRemoteComputerName - credential $cred |Where{$_.DeviceID.StartsWith("PCI\VEN_10DE") -or $_.DeviceID.StartsWith("PCI\VEN_1002")}
-credential are only needed if the actual user running powershell isn't administrator of remote machine.
Hi I needed to do some thing like this once so i wrote some code that can send any ps code to a remote computes and display the results in the ps window on your pc.
Just remember to enable powershell remoting on both pc's.
function remote-pscode ($ServerName,$UserName,$password,$PSCode)
{
$global:RemoteCode = $args[0]
Write-Host $RemoteCode
$conprops = (Get-Host).UI.RawUI
$buffsize = $conprops.BufferSize
$buffsize.Height = 800
$conprops.BufferSize= $buffsize
# Set the user name you would like to use for the connection
$global:RemoteUserName = $UserName
$global:RemoteServerName = $ServerName
# Set the password you would like to use for the connection
# Check to see if you have a file on you drive c:\cred.txt with a password to use in it,if you don't it will create one
# for you and ask you for the password you would like to use
$global:RemotePassword = convertto-securestring $password -AsPlainText -Force
$global:credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $RemoteUserName,$RemotePassword
#Create a connection to the remote computer , put a list of IPAddresses or Computer Names.
$global:session = new-PSSession -ComputerName $RemoteServerName -Credential $credentials
$ScriptBlock = $executioncontext.invokecommand.NewScriptBlock($RemoteCode)
invoke-command -Session $session -ScriptBlock $ScriptBlock
#Close the sessions that where created
$global:closesession = Get-PSSession
Remove-PSSession -Session $closesession
}
remote-pscode -ServerName "NameOfRemotePC" -UserName "UserName" -password "password" -PSCode "any powershell code you want to send to the remote pc"
Several things here: put your PS commands in a script block (or a script). Also, why don't you simply use wmic.exe ?