- Adbot
-
ADBOT LOVES YOU
|
|
#
?
May 15, 2024 03:54
|
|
- myron cope
- Apr 21, 2009
-
|
I just tried the same setup on Windows 7 and I think Braintist is right; there was no popup and I didn't bother messing with a window style.
I think that worked, although I did both. Thanks!
|
#
?
Jan 22, 2015 16:08
|
|
- MF_James
- May 8, 2008
-
I CANNOT HANDLE BEING CALLED OUT ON MY DUMBASS OPINIONS ABOUT ANTI-VIRUS AND SECURITY. I REALLY LIKE TO THINK THAT I KNOW THINGS HERE
INSTEAD I AM GOING TO WHINE ABOUT IT IN OTHER THREADS SO MY OPINION CAN FEEL VALIDATED IN AN ECHO CHAMBER I LIKE
|
Powershell total noob here (also new to scripting in general yay)
What I'm trying to do is import a CSV, with user input not a predefined file/location, the CSV will have 3 columns with headers (it might change and have no headers but I know how to fix that). The headers are Location,Region,Division. There will likely be a few hundred rows that I have to step through.
code:import-module ActiveDirectory
Import-CSV -prompt | foreach-object
{
#utilizing location to get full computer name#
$Store = "STORE"+$_.Location
$Host = "HOST"+$_.Location
#Utilizing full computer name to get object#
$StoreDN = (Get-ADUser -identity $Store)
$HostDN = (Get-ADUser -identity $Host)
$targetOU = (ou=$_.region, ou=$_.division, ou=PROD, ou=Stores, DC=my.domain.name)
Move-ADObject -identity $StoreDN -TargetPath $TargetOU
Move-ADObject -identity $HostDN -TargetPath $TargetOU
}
So, each location has 2 objects associated with it, there is a prefix that identifies between the 2, the prefixes are HOST/GUEST, both objects will move to the same region/division, and all objets will move to the location path - domain/stores/prod/division/region region being the lowest level OU. Region/division will change based on whatever location we are dealing with, hence the need for region/division in the CSV columns.
Am I headed down the right path here? We are also looking at doing some sort of logging for success/failure, how would I go about doing that?
MF_James fucked around with this message at 21:58 on Jan 22, 2015
|
#
?
Jan 22, 2015 21:46
|
|
- Briantist
- Dec 5, 2003
-
The Professor does not approve of your post.
-
Lipstick Apathy
|
Powershell total noob here (also new to scripting in general yay)
What I'm trying to do is import a CSV, with user input not a predefined file/location, the CSV will have 3 columns with headers (it might change and have no headers but I know how to fix that). The headers are Location,Region,Division. There will likely be a few hundred rows that I have to step through.
code:import-module ActiveDirectory
Import-CSV -prompt | foreach-object
{
#utilizing location to get full computer name#
$Store = "STORE"+$_.Location
$Host = "HOST"+$_.Location
#Utilizing full computer name to get object#
$StoreDN = (Get-ADUser -identity $Store)
$HostDN = (Get-ADUser -identity $Host)
$targetOU = (ou=$_.region, ou=$_.division, ou=PROD, ou=Stores, DC=my.domain.name)
Move-ADObject -identity $StoreDN -TargetPath $TargetOU
Move-ADObject -identity $HostDN -TargetPath $TargetOU
}
So, each location has 2 objects associated with it, there is a prefix that identifies between the 2, the prefixes are HOST/GUEST, both objects will move to the same region/division, and all objets will move to the location path - domain/stores/prod/division/region region being the lowest level OU. Region/division will change based on whatever location we are dealing with, hence the need for region/division in the CSV columns.
Am I headed down the right path here? We are also looking at doing some sort of logging for success/failure, how would I go about doing that?
I have a few points:
- Import-CSV doesn't take a "-Prompt" parameter. You can handle this a few different ways. You can use Read-Host to get user input which might be the easiest to understand if you're new to this:
code:$csv = Read-Host -Prompt 'Where is the CSV?!'
Import-Csv -Path $csv
For bonus points, use Test-Path to make sure the file given by the user actually exists.
What I'd prefer instead is to make the script itself take a -Path parameter, and make it required. If the user doesn't supply a path when calling the script, Powershell will prompt for you. To do that, you'd add stuff like this to the top of the script:
code:[CmdletBinding()]
param(
[Parameter(
Mandatory = $true,
HelpMessage = 'Enter the path to the CSV file.'
)]
[ValidateScript( { $_ | Test-Path -PathType Leaf } )]
[String]
$Path
)
# your code here
$Path | Import-Csv | ForEach-Object {
# ...
}
# your code here
This code also makes sure whatever the user enters exists on the file system and is a file (Leaf) rather than a folder. It's a lot more elegant and it's the "powershell way" of doing it, but it can be tough to understand if you're new to both this language and scripting itself.
- If you're trying to retrieve a computer object from AD, you should probably use Get-ADComputer rather than Get-ADUser.
- Your assignment of $targetOU is at best creating an array, but is probably invalid as written. Try this:
code:$targetOU = "ou=$($_.region),ou=$($_.division),ou=PROD,ou=Stores,DC=my.domain.name"
You can use variables directly in a double quoted string, but if you're trying to access a property with dot notaton it won't work. $(...) is a sub-expression and can be used in strings. Inside the parentheses you can use variables, cmdlets, entire pipelines. The result of all the code is the result of the sub-expression and will be put into the string.
- Regarding building the $targetOU string, also just be careful that your regions and divisions don't contain commas. If they do, you need to escape them with \, (for AD's sake, not powershell).
- Your variable names for $StoreDN and $HostDN imply that you think you'll get a DN as a string in response from Get-ADUser (or Get-ADComputer). You will in fact receive a complete object. It doesn't matter that you called the variables what you did, but you should be aware of what you'll have.
For the most part though, yeah it seems that you are headed down the right path.
For catching errors, you probably want to wrap some of your code in try/catch blocks, which can be a bit daunting for a beginner. This kind of seems like a one-shot type of task rather than something you'll be running a whole lot. Is that accurate? If so, you might just want to step through the code in Powershell ISE bit by bit. Here's a simple try/catch you could do:
code:Import-CSV -prompt | foreach-object
{
#utilizing location to get full computer name#
$Store = "STORE"+$_.Location
$Host = "HOST"+$_.Location
#Utilizing full computer name to get object#
try {
$StoreDN = (Get-ADUser -identity $Store)
$HostDN = (Get-ADUser -identity $Host)
$targetOU = (ou=$_.region, ou=$_.division, ou=PROD, ou=Stores, DC=my.domain.name)
Move-ADObject -identity $StoreDN -TargetPath $TargetOU
Move-ADObject -identity $HostDN -TargetPath $TargetOU
} catch {
$_ # set a breakpoint here so the whole script stops and you can see what happened?
}
}
|
#
?
Jan 23, 2015 01:17
|
|
- MF_James
- May 8, 2008
-
I CANNOT HANDLE BEING CALLED OUT ON MY DUMBASS OPINIONS ABOUT ANTI-VIRUS AND SECURITY. I REALLY LIKE TO THINK THAT I KNOW THINGS HERE
INSTEAD I AM GOING TO WHINE ABOUT IT IN OTHER THREADS SO MY OPINION CAN FEEL VALIDATED IN AN ECHO CHAMBER I LIKE
|
Thanks for taking a look.
Yes this is a one off script (I will take it with me and make it better in the event I need to use it elsewhere in my career)
I didn't really know how to prompt the user and my googling wasn't turning up much, the user will be me in this case, but I'll be running the script a few times with multiple files and I feel it's easier to deal with it by manually inputting than figuring out how to do it completely automated especially consdering my point above.
I can't believe I didn't notice I had Get-ADUser instad of Get-ADComputer.
Yeah I named the variables a while ago and realize it's not the DN I'm getting, but I don't see a need to change them at this point honestly.
With the $TargetOU, I'm guessing it's not exactly the best way to point to the OU that I want, but I found it slightly easier in my head to pass it as a variable string to the GET-ADobject than it was to put the whole structure into each Get. Thanks again for pointing out how that would essentially blow up how I had it written.
|
#
?
Jan 23, 2015 02:07
|
|
- Spazz
- Nov 17, 2005
-
|
Crossposting this poo poo in here because I'm about to set something on fire...
http://stackoverflow.com/questions/27975936/new-webserviceproxy-failing-to-authenticate-with-ntlm
I'm honestly wondering if I need to hack something together to make this stupid thing work.
|
#
?
Jan 23, 2015 16:05
|
|
- Space Whale
- Nov 6, 2014
-
|
My workplace has no DBA. It's basically been badly administrated by the back end devs and architect round robin. I'd rather not play "copy and paste poo poo into scripts in management studio" so I figure it's time to learn a powershell.
Coming into this as a back end dev, what are some good ways to avoid making stupid mistakes?
Also, in general, what's a good way to tell that you need to start brow beating management into getting a DBA in terms of time devs spend doing it, the schema sucking, or just the size of your company and the amount of data flying in? We're completely dependent on our data to make money or do business at all, so I'd think that alone would justify it, but we have some very heads-down back end devs who just do as told and nobody's made a stink yet.
|
#
?
Jan 26, 2015 17:23
|
|
- New Yorp New Yorp
- Jul 18, 2003
-
Only in Kenya.
-
Pillbug
|
My workplace has no DBA. It's basically been badly administrated by the back end devs and architect round robin. I'd rather not play "copy and paste poo poo into scripts in management studio" so I figure it's time to learn a powershell.
Coming into this as a back end dev, what are some good ways to avoid making stupid mistakes?
Also, in general, what's a good way to tell that you need to start brow beating management into getting a DBA in terms of time devs spend doing it, the schema sucking, or just the size of your company and the amount of data flying in? We're completely dependent on our data to make money or do business at all, so I'd think that alone would justify it, but we have some very heads-down back end devs who just do as told and nobody's made a stink yet.
Are you a .NET shop? Use SSDT.
|
#
?
Jan 26, 2015 17:29
|
|
- Space Whale
- Nov 6, 2014
-
|
Are you a .NET shop? Use SSDT.
Yes.
Welp, learning new things is fun!
|
#
?
Jan 26, 2015 18:12
|
|
- New Yorp New Yorp
- Jul 18, 2003
-
Only in Kenya.
-
Pillbug
|
Yes.
Welp, learning new things is fun!
Yeah, then use SSDT to source control your schema. That's the thing you care about... change scripts are an artifact of transforming one version of the schema into another schema. They don't need to be source controlled as long as you have something that can analyze an existing database and generate a changescript. SSDT generates DACPACs, which are just a canonical version of your DB schema. You can publish a DACPAC to an existing database, which analyzes the differences, creates a change script, and executes it.
Integrate that into your release process and you're done.
|
#
?
Jan 26, 2015 19:17
|
|
- Space Whale
- Nov 6, 2014
-
|
Yeah, then use SSDT to source control your schema. That's the thing you care about... change scripts are an artifact of transforming one version of the schema into another schema. They don't need to be source controlled as long as you have something that can analyze an existing database and generate a changescript. SSDT generates DACPACs, which are just a canonical version of your DB schema. You can publish a DACPAC to an existing database, which analyzes the differences, creates a change script, and executes it.
Integrate that into your release process and you're done.
I'm not changing the schema right now, I'm working on the data. I'm merging and deleting entries.
Is there still something I should be doing besides backups of the data before and after?
|
#
?
Jan 26, 2015 20:11
|
|
- FISHMANPET
- Mar 3, 2007
-
Sweet 'N Sour
Can't
Melt
Steel Beams
|
This language is such garbage. Never have I dealt with a language where I have to spend 90% of my time just fighting the language because it doesn't behave rationally.
I'm trying to change the local admin password on a bunch of servers. For reasons I don't understand WMIC isn't working so I'm trying to use invoke-command to run a command on the remote machine. I want to pass my script a list of servers that I want it to change the password on, and then I want it to return a result of what happens on each server, either sucess or failure.
I keep wrapping things in try-catch blocsk and invoke-command just returns garbage as far as error handling goes. I want invoke-command to return an error, but the only way it will return an error is if the the computer you're running on doesn't exist. And it doesn't actually return an error that can be caught, I have to run it as a job and then do some fuckery to get an actual error out of it. If I want to get an error out of my script block that I'm running on the remote machine, that's a whole other can of worms. This doesn't seem that complicated, and one of those vaunted use cases that Powershell is supposedly great for. Automate a task on a bunch of servers, and let me know how it goes (is it the wanting to know how it goes part that I'm not supposed to be doing with powershell?)
I'm about ready to find something to treat as a physical manifestation of powershell, so I can throw it across the room because it's all garbage. I've been fighting all week with this and all Powershell does is get in my way. Maybe it's because I'm used to programming in other languages that actually make sense? Do I need a lobotomy to think in Powershell terms?
Here's my code, for reference, maybe I'm going about this entirely the wrong way?
code:Param(
[Parameter(Mandatory=$true)]
[String[]]
$ComputerNames,
[Parameter(Mandatory=$true)]
[String]
$LocalAccount
)
$password = Read-Host -Prompt "Enter Password Base" -AsSecureString
$RemoteChangeScript = {
Param(
[Parameter(Mandatory=$true, Position=1)]
[SecureString]
$Password,
[Parameter(Mandatory=$true, Position=2)]
[String]
$LocalAccount,
#This is here so I can record what the server name that the script connected to was, sometimes the DNS records get messed up, it can be nice to have this.
[Parameter(Mandatory=$true, Position=3)]
[String]
$TargettedServerName
)
$LocalUsers = Get-WmiObject Win32_UserAccount -Filter "LocalAccount=true" | Foreach {$_.Name}
foreach ($User in $LocalUsers)
{
if ($LocalAccount -ne $User)
{
Write-Warning "Server: '$($TargettedServerName)' has a local account '$($User)' whos password is NOT being changed by this script"
}
}
$password.AppendChar($env:computername[-1].ToString().ToLower())
$password.AppendChar($env:computername[-2].ToString().ToLower())
try
{
$objUser = [ADSI]"WinNT://localhost/$($LocalAccount), user"
$objUser.psbase.Invoke("SetPassword", [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)))
$Properties = @{
TargettedServerName = $TargettedServerName
Username = $LocalAccount
RealServerName = $env:computername
Error = "Sucess"
}
}
catch
{
Write-Error "Error changing password for user:$($LocalAccount) on server:$($TargettedServerName)"
$Properties = @{
TargettedServerName = $TargettedServerName
Username = $LocalAccount
RealServerName = $env:computername
Error = $_.Exception.Message
}
}
finally
{
$ReturnData = New-Object PSObject -Property $Properties
$ReturnData
}
}
foreach ($Computer in $ComputerNames)
{
$Return = Invoke-Command -ScriptBlock $RemoteChangeScript -ArgumentList @($password, $LocalAccount, $Computer) -ComputerName $Computer -AsJob
#$Return = Invoke-Command -ScriptBlock {echo "helo"} -ComputerName $Computer -AsJob
try
{
Write-Warning "$computer try"
$Result = Receive-Job $Return -ErrorAction Stop
#Write-Warning $result
Write-Warning "hello this is the try block"
#Write-Warning $result
}
catch
{
Write-Warning "$computer catch"
$Properties = @{
TargettedServerName = $Computer
Username = $LocalAccount
RealServerName = $Computer
Error = $_.Exception.Message
}
$Result = New-Object PSObject -Property $Properties
}
Write-Output $Result
}
#$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword))
|
#
?
Jan 29, 2015 01:14
|
|
- Dr. Arbitrary
- Mar 15, 2006
-
-
Bleak Gremlin
|
This doesn't seem that complicated, and one of those vaunted use cases that Powershell is supposedly great for.
I was just thinking that there HAS to be an easy way to do this but when I searched for it, it's apparently really complicated for reasons that I don't understand.
This is the kind of thing that there ought to be a commandlet for.
|
#
?
Jan 29, 2015 07:38
|
|
- Fenrisulfr
- Oct 14, 2012
-
|
Is there some reason you're not just doing this (modified for your other requirements, of course):
code:$objUser = [ADSI]"WinNT://$computer/$user,user"
$objUser.SetPassword($password)
You shouldn't need to do any Invoke-Commands, the ADSI object can point to the server in its definition. You may need a "$objUser.SetInfo()" to push the password change but I'm not sure about that.
|
#
?
Jan 29, 2015 09:59
|
|
- FISHMANPET
- Mar 3, 2007
-
Sweet 'N Sour
Can't
Melt
Steel Beams
|
I don't think our firewall is allowing the ADSI connection through, but I can't really be sure because the error I get is not especially useful:
code:The following exception occurred while retrieving member "SetPassword": "The network path was not found.
"
At line:1 char:1
+ $objuser.SetPassword("password")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
+ FullyQualifiedErrorId : CatchFromBaseGetMember
And that's not really a useful error message, the machine clearly exists. I can't find any useful information on what this error means to be able to debug it.
|
#
?
Jan 29, 2015 17:05
|
|
- Fenrisulfr
- Oct 14, 2012
-
|
I don't think our firewall is allowing the ADSI connection through, but I can't really be sure because the error I get is not especially useful:
code:The following exception occurred while retrieving member "SetPassword": "The network path was not found.
"
At line:1 char:1
+ $objuser.SetPassword("password")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ExtendedTypeSystemException
+ FullyQualifiedErrorId : CatchFromBaseGetMember
And that's not really a useful error message, the machine clearly exists. I can't find any useful information on what this error means to be able to debug it.
You may have already tried this, but you can a) check that your ADSI connection string is what you expect by writing it to output; and/or b) do a Test-Connection $computer to make sure that Powershell can connect to the server. If both of those look good, it may be a firewall issue like you said, or maybe Remote Management is disabled on those servers: https://msdn.microsoft.com/en-us/library/dd759202.aspx.
|
#
?
Jan 29, 2015 17:35
|
|
- MF_James
- May 8, 2008
-
I CANNOT HANDLE BEING CALLED OUT ON MY DUMBASS OPINIONS ABOUT ANTI-VIRUS AND SECURITY. I REALLY LIKE TO THINK THAT I KNOW THINGS HERE
INSTEAD I AM GOING TO WHINE ABOUT IT IN OTHER THREADS SO MY OPINION CAN FEEL VALIDATED IN AN ECHO CHAMBER I LIKE
|
Ok, so I've gotten very far in my move ad computer script after running it 100x and troubleshooting. I'm now a bit stuck with a mostly cosmetic issue.
code:import-module ActiveDirectory
$Path = Read-Host -Prompt "CSV Location Please, Sir"
if ((Test-Path -path $Path))
{
$csv = Import-CSV $Path
foreach($item in $csv)
{
$Store = "STORE"+$item.Location
$VMHost = "HOST"+$item.Location
$targetOU = "ou=" + $item.region + ",ou="+ $item.division + ",ou=PROD,ou=Stores,DC=qastr,DC=qapos,DC=bfrc"
try{$teststore = Get-ADComputer -identity $Store}
catch{$Store + "Could not be found" | Out-File C:\error.txt -Append}
try{
if(!$error){Get-ADComputer -identity $Store | Move-ADObject -TargetPath $TargetOU}
else{$error.clear}
}
catch{$Store + "Could not be moved" | Out-File C:\error.txt -Append}
try{$testhost = Get-ADComputer -identity $VMHost}
catch{$VMHost + "Could not be found" | Out-File C:\error.txt -Append}
try{
if(!$error){Get-ADComputer -identity $VMHost | Move-ADObject -TargetPath $TargetOU}
else{$error.clear}
}
catch{$VMHost + "Could not be moved" | Out-File C:\error.txt -Append}
}
}
else{Write-Output "The CSV path failed"}
So, the problem I'm having is that when you do a $error.clear it shits up the powershell window, so I wrapped them in an if/else so that if there's NOT an error, it should move the computer, if there was an error it should clear the error and move on to the catch which is outputting the computer name and telling me it couldn't find it or it couldn't move it depending on where it is in the script. The problem I'm having is that it's ALWAYS clearing $error, since I'm running this against 4400+ objects... that's a lot of making GBS threads all over my window that I don't want, does anyone know WHY my if/else isn't functioning properly, or is it something else about how $error.clear works that I don't understand?
MF_James fucked around with this message at 19:22 on Jan 29, 2015
|
#
?
Jan 29, 2015 19:16
|
|
- Zaepho
- Oct 31, 2013
-
|
So, the problem I'm having is that when you do a $error.clear it shits up the powershell window, so I wrapped them in an if/else so that if there's NOT an error, it should move the computer, if there was an error it should clear the error and move on to the catch which is outputting the computer name and telling me it couldn't find it or it couldn't move it depending on where it is in the script. The problem I'm having is that it's ALWAYS clearing $error, since I'm running this against 4400+ objects... that's a lot of making GBS threads all over my window that I don't want, does anyone know WHY my if/else isn't functioning properly, or is it something else about how $error.clear works that I don't understand?
Pipe the result of $error.clear to null
code:else {
$Error.Clear | out-null
}
|
#
?
Jan 29, 2015 19:39
|
|
- MF_James
- May 8, 2008
-
I CANNOT HANDLE BEING CALLED OUT ON MY DUMBASS OPINIONS ABOUT ANTI-VIRUS AND SECURITY. I REALLY LIKE TO THINK THAT I KNOW THINGS HERE
INSTEAD I AM GOING TO WHINE ABOUT IT IN OTHER THREADS SO MY OPINION CAN FEEL VALIDATED IN AN ECHO CHAMBER I LIKE
|
Pipe the result of $error.clear to null
code:else {
$Error.Clear | out-null
}
Cool, that works, but I'm curious, isn't this just circumventing the issue at hand? It's causing it to nullify the output so I don't see it, but my initial oddity is still there, why is it running BOTH the if and the else? It should run the if (provided !$error returns true) and then, provided if/else works the same as it does in C++/C# and follows any sort of sense, it should NOT run the else statement.
|
#
?
Jan 29, 2015 20:41
|
|
- Spazz
- Nov 17, 2005
-
|
FYI it's $error.clear() to silently flush it.
|
#
?
Jan 29, 2015 20:48
|
|
- Briantist
- Dec 5, 2003
-
The Professor does not approve of your post.
-
Lipstick Apathy
|
This language is such garbage. Never have I dealt with a language where I have to spend 90% of my time just fighting the language because it doesn't behave rationally.
I'm trying to change the local admin password on a bunch of servers. For reasons I don't understand WMIC isn't working so I'm trying to use invoke-command to run a command on the remote machine. I want to pass my script a list of servers that I want it to change the password on, and then I want it to return a result of what happens on each server, either sucess or failure.
I keep wrapping things in try-catch blocsk and invoke-command just returns garbage as far as error handling goes. I want invoke-command to return an error, but the only way it will return an error is if the the computer you're running on doesn't exist. And it doesn't actually return an error that can be caught, I have to run it as a job and then do some fuckery to get an actual error out of it. If I want to get an error out of my script block that I'm running on the remote machine, that's a whole other can of worms. This doesn't seem that complicated, and one of those vaunted use cases that Powershell is supposedly great for. Automate a task on a bunch of servers, and let me know how it goes (is it the wanting to know how it goes part that I'm not supposed to be doing with powershell?)
I'm about ready to find something to treat as a physical manifestation of powershell, so I can throw it across the room because it's all garbage. I've been fighting all week with this and all Powershell does is get in my way. Maybe it's because I'm used to programming in other languages that actually make sense? Do I need a lobotomy to think in Powershell terms?
Here's my code, for reference, maybe I'm going about this entirely the wrong way?
code:# <snip>
try
{
$objUser = [ADSI]"WinNT://localhost/$($LocalAccount), user"
$objUser.psbase.Invoke("SetPassword", [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)))
$Properties = @{
TargettedServerName = $TargettedServerName
Username = $LocalAccount
RealServerName = $env:computername
Error = $null
}
}
catch
{
Write-Error "Error changing password for user:$($LocalAccount) on server:$($TargettedServerName)"
$Properties = @{
TargettedServerName = $TargettedServerName
Username = $LocalAccount
RealServerName = $env:computername
Error = $_ #.Exception.Message
}
}
finally
{
$ReturnData = New-Object PSObject -Property $Properties
$ReturnData
}
}
# <snip>
foreach ($Computer in $ComputerNames)
{
$Return = Invoke-Command -ScriptBlock $RemoteChangeScript -ArgumentList @($password, $LocalAccount, $Computer) -ComputerName $Computer
#$Return = Invoke-Command -ScriptBlock {echo "helo"} -ComputerName $Computer -AsJob
try
{
Write-Warning "$computer try"
# $Result = Receive-Job $Return -ErrorAction Stop
#Write-Warning $result
# Write-Warning "hello this is the try block"
#Write-Warning $result
if ($Return.Error) {
throw $Return.Error
}
}
catch
{
Write-Warning "$computer catch"
$Properties = @{
TargettedServerName = $Computer
Username = $LocalAccount
RealServerName = $Computer
Error = $_.Exception.Message
}
$Result = New-Object PSObject -Property $Properties
}
Write-Output $Result
}
#$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword))
What about something like this?
I took out -AsJob.
You're already returning an object which is good, and it already has an error property, even better.
As you pointed out, you can't throw an exception on the remote side and catch it on the local side. That's because it's a completely different session or runspace. Any objects sent back are serialized and so are no longer "live".
So I changed the code a bit so that when there is no error, it just sets the error property in your object to $null. When there is an exception, just use $_ and don't bother with the internal exception's message (right now we just want to pass this back to the caller).
Then back on the calling side, you check for an error in the property. At this point, you could JUST use this method (an if statement) instead of try/catch, but I'm assuming you want to use try/catch so if the error exists, then we just throw the error as is (which you can then catch and handle as necessary).
I haven't tested this yet, but it's fairly workable and much easier than using jobs.
Jobs give the added benefit of asynchronous-ness but your code as is could easily fail if the remote job were not yet completed. So you'd need more code to check on the status of the jobs that are waiting and receive the results when necessary.
|
#
?
Jan 29, 2015 21:27
|
|
- Zaepho
- Oct 31, 2013
-
|
Cool, that works, but I'm curious, isn't this just circumventing the issue at hand? It's causing it to nullify the output so I don't see it, but my initial oddity is still there, why is it running BOTH the if and the else? It should run the if (provided !$error returns true) and then, provided if/else works the same as it does in C++/C# and follows any sort of sense, it should NOT run the else statement.
i just noticed you have your if all contained on a single line and then a line break and then the else. try:
code:if (stuff) {
Do things
} else {
Do Other Stuff
}
I'm betting the line break is confusing it.
FYI it's $error.clear() to silently flush it.
I was wondering if the method didn't need the () to run but I wasn't going to mess with code that was working without trying it myself or knowing for sure.
|
#
?
Jan 29, 2015 21:40
|
|
- MF_James
- May 8, 2008
-
I CANNOT HANDLE BEING CALLED OUT ON MY DUMBASS OPINIONS ABOUT ANTI-VIRUS AND SECURITY. I REALLY LIKE TO THINK THAT I KNOW THINGS HERE
INSTEAD I AM GOING TO WHINE ABOUT IT IN OTHER THREADS SO MY OPINION CAN FEEL VALIDATED IN AN ECHO CHAMBER I LIKE
|
I don't think it has to do with that. *EDIT* it doesn't, I changed the script to be "cleaner" for myself and the ifelse is all on a single line.
I noticed some odd behavior. If I open powershell and run the script immediately, it only runs $error.clear on the things I would expect it to (I have 7 cases where it will fail and 7 where it will succeed), so I get 7 $error.clear messages, when I run it a second time without closing/reopening the CLI I will get a clear message on all 14 cases, but the 7 that I expect to succeed still do succeed.
|
#
?
Jan 29, 2015 21:55
|
|
- Briantist
- Dec 5, 2003
-
The Professor does not approve of your post.
-
Lipstick Apathy
|
I don't think it has to do with that. *EDIT* it doesn't, I changed the script to be "cleaner" for myself and the ifelse is all on a single line.
I noticed some odd behavior. If I open powershell and run the script immediately, it only runs $error.clear on the things I would expect it to (I have 7 cases where it will fail and 7 where it will succeed), so I get 7 $error.clear messages, when I run it a second time without closing/reopening the CLI I will get a clear message on all 14 cases, but the 7 that I expect to succeed still do succeed.
Have you changed your to code use $Error.Clear() yet instead of just .Clear? You definitely need the parentheses.
Also, I'm curious why you're using $Error in the first place. It looks like you're doing it to catch errors at multiple points in the process so that you can tell which parts of the process failed. The better way to do this, I think, is to use nested try/catch blocks and/or to use multiple catch blocks that catch specific exceptions instead of just catching everything.
What if it looked like this:
code:import-module ActiveDirectory
$Path = Read-Host -Prompt "CSV Location Please, Sir"
if ((Test-Path -path $Path))
{
$csv = Import-CSV $Path
foreach($item in $csv)
{
$Store = "STORE"+$item.Location
$VMHost = "HOST"+$item.Location
$targetOU = "ou=" + $item.region + ",ou="+ $item.division + ",ou=PROD,ou=Stores,DC=qastr,DC=qapos,DC=bfrc"
try {
$teststore = Get-ADComputer -identity $Store
try {
Get-ADComputer -identity $Store | Move-ADObject -TargetPath $TargetOU
try {
$testhost = Get-ADComputer -identity $VMHost
try {
Get-ADComputer -identity $VMHost | Move-ADObject -TargetPath $TargetOU
} catch {
$VMHost + "Could not be moved" | Out-File C:\error.txt -Append
}
} catch {
$VMHost + "Could not be found" | Out-File C:\error.txt -Append
}
} catch {
$Store + "Could not be moved" | Out-File C:\error.txt -Append
}
} catch {
$Store + "Could not be found" | Out-File C:\error.txt -Append
}
}
}
else{Write-Output "The CSV path failed"}
So that's how it would look with nested try catch. Even better would be to catch specific exceptions:
code:import-module ActiveDirectory
$Path = Read-Host -Prompt "CSV Location Please, Sir"
if ((Test-Path -path $Path))
{
$csv = Import-CSV $Path
foreach($item in $csv)
{
$Store = "STORE"+$item.Location
$VMHost = "HOST"+$item.Location
$targetOU = "ou=" + $item.region + ",ou="+ $item.division + ",ou=PROD,ou=Stores,DC=qastr,DC=qapos,DC=bfrc"
try {
# $teststore = Get-ADComputer -identity $Store # Not needed anymore
Get-ADComputer -identity $Store | Move-ADObject -TargetPath $TargetOU
# $testhost = Get-ADComputer -identity $VMHost # Not needed anymore
Get-ADComputer -identity $VMHost | Move-ADObject -TargetPath $TargetOU
} catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
$Store + "Could not be found" | Out-File C:\error.txt -Append
} catch [Microsoft.ActiveDirectory.Management.SomeMoveObjectException] { # I made this one up
$Store + "Could not be moved" | Out-File C:\error.txt -Append
}
}
}
else{Write-Output "The CSV path failed"}
This is much shorter, much cleaner. You'll just have to find the correct exception class for the Move-ADObject call. It also obviates the need for calling Get-ADComputer 4 times since you don't need to test the object first.
The only thing you might have to do is add -ErrorAction Stop onto both the Get- and Move- calls to ensure that the errors are terminating errors (and therefore will be caught by try/catch).
|
#
?
Jan 29, 2015 22:19
|
|
- MF_James
- May 8, 2008
-
I CANNOT HANDLE BEING CALLED OUT ON MY DUMBASS OPINIONS ABOUT ANTI-VIRUS AND SECURITY. I REALLY LIKE TO THINK THAT I KNOW THINGS HERE
INSTEAD I AM GOING TO WHINE ABOUT IT IN OTHER THREADS SO MY OPINION CAN FEEL VALIDATED IN AN ECHO CHAMBER I LIKE
|
Have you changed your to code use $Error.Clear() yet instead of just .Clear? You definitely need the parentheses.
Also, I'm curious why you're using $Error in the first place. It looks like you're doing it to catch errors at multiple points in the process so that you can tell which parts of the process failed. The better way to do this, I think, is to use nested try/catch blocks and/or to use multiple catch blocks that catch specific exceptions instead of just catching everything.
What if it looked like this:
code:import-module ActiveDirectory
$Path = Read-Host -Prompt "CSV Location Please, Sir"
if ((Test-Path -path $Path))
{
$csv = Import-CSV $Path
foreach($item in $csv)
{
$Store = "STORE"+$item.Location
$VMHost = "HOST"+$item.Location
$targetOU = "ou=" + $item.region + ",ou="+ $item.division + ",ou=PROD,ou=Stores,DC=qastr,DC=qapos,DC=bfrc"
try {
$teststore = Get-ADComputer -identity $Store
try {
Get-ADComputer -identity $Store | Move-ADObject -TargetPath $TargetOU
try {
$testhost = Get-ADComputer -identity $VMHost
try {
Get-ADComputer -identity $VMHost | Move-ADObject -TargetPath $TargetOU
} catch {
$VMHost + "Could not be moved" | Out-File C:\error.txt -Append
}
} catch {
$VMHost + "Could not be found" | Out-File C:\error.txt -Append
}
} catch {
$Store + "Could not be moved" | Out-File C:\error.txt -Append
}
} catch {
$Store + "Could not be found" | Out-File C:\error.txt -Append
}
}
}
else{Write-Output "The CSV path failed"}
So that's how it would look with nested try catch. Even better would be to catch specific exceptions:
code:import-module ActiveDirectory
$Path = Read-Host -Prompt "CSV Location Please, Sir"
if ((Test-Path -path $Path))
{
$csv = Import-CSV $Path
foreach($item in $csv)
{
$Store = "STORE"+$item.Location
$VMHost = "HOST"+$item.Location
$targetOU = "ou=" + $item.region + ",ou="+ $item.division + ",ou=PROD,ou=Stores,DC=qastr,DC=qapos,DC=bfrc"
try {
# $teststore = Get-ADComputer -identity $Store # Not needed anymore
Get-ADComputer -identity $Store | Move-ADObject -TargetPath $TargetOU
# $testhost = Get-ADComputer -identity $VMHost # Not needed anymore
Get-ADComputer -identity $VMHost | Move-ADObject -TargetPath $TargetOU
} catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
$Store + "Could not be found" | Out-File C:\error.txt -Append
} catch [Microsoft.ActiveDirectory.Management.SomeMoveObjectException] { # I made this one up
$Store + "Could not be moved" | Out-File C:\error.txt -Append
}
}
}
else{Write-Output "The CSV path failed"}
This is much shorter, much cleaner. You'll just have to find the correct exception class for the Move-ADObject call. It also obviates the need for calling Get-ADComputer 4 times since you don't need to test the object first.
The only thing you might have to do is add -ErrorAction Stop onto both the Get- and Move- calls to ensure that the errors are terminating errors (and therefore will be caught by try/catch).
Honestly? I'm doing it this way because I don't know any better! Been figuring stuff out through googling and trial/error
|
#
?
Jan 29, 2015 22:38
|
|
- Zaepho
- Oct 31, 2013
-
|
Even better would be to catch specific exceptions:
code:import-module ActiveDirectory
$Path = Read-Host -Prompt "CSV Location Please, Sir"
if ((Test-Path -path $Path))
{
$csv = Import-CSV $Path
foreach($item in $csv)
{
$Store = "STORE"+$item.Location
$VMHost = "HOST"+$item.Location
$targetOU = "ou=" + $item.region + ",ou="+ $item.division + ",ou=PROD,ou=Stores,DC=qastr,DC=qapos,DC=bfrc"
try {
# $teststore = Get-ADComputer -identity $Store # Not needed anymore
Get-ADComputer -identity $Store | Move-ADObject -TargetPath $TargetOU
# $testhost = Get-ADComputer -identity $VMHost # Not needed anymore
Get-ADComputer -identity $VMHost | Move-ADObject -TargetPath $TargetOU
} catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
$Store + "Could not be found" | Out-File C:\error.txt -Append
} catch [Microsoft.ActiveDirectory.Management.SomeMoveObjectException] { # I made this one up
$Store + "Could not be moved" | Out-File C:\error.txt -Append
}
}
}
else{Write-Output "The CSV path failed"}
This is much shorter, much cleaner. You'll just have to find the correct exception class for the Move-ADObject call. It also obviates the need for calling Get-ADComputer 4 times since you don't need to test the object first.
The only thing you might have to do is add -ErrorAction Stop onto both the Get- and Move- calls to ensure that the errors are terminating errors (and therefore will be caught by try/catch).
I like this one, my only alteration would be a final catch for everything else and I would log the exception message to make it easier to troubleshoot when things go wrong.
Specifically:
code:$($_.Exception.Message)
|
#
?
Jan 29, 2015 23:31
|
|
- Briantist
- Dec 5, 2003
-
The Professor does not approve of your post.
-
Lipstick Apathy
|
I like this one, my only alteration would be a final catch for everything else and I would log the exception message to make it easier to troubleshoot when things go wrong.
Specifically:
code:$($_.Exception.Message)
Yeah not a bad idea. Depends on the situation. In some cases, I like to let it just not catch the exception and then interrupt the script, so that I can then decide how to handle it (and whether it makes sense for the script to keep running).
Sometimes I know I can safely "ignore" the whole iteration so I catch all and "skip" whatever I'm doing that for that item, and/or log it.
If nothing else, it would be a great place to put a breakpoint!
|
#
?
Jan 30, 2015 22:09
|
|
- Dr. Arbitrary
- Mar 15, 2006
-
-
Bleak Gremlin
|
Anyone know a good way to get started on desired state configuration?
I've got some basic templates, like for adding IIS, but I'm not sure how I would do other roles or features.
Edit:
Here's what I'm looking at:
http://blogs.technet.com/b/privatecloud/archive/2013/08/30/introducing-powershell-desired-state-configuration-dsc.aspx
In the example, where it says
WindowsFeature IIS
{
Ensure = "present"
Name = "Web-Server"
}
Web-Server comes from Get-WindowsFeature
Is the "IIS" part just arbitrary?
Dr. Arbitrary fucked around with this message at 16:01 on Jan 31, 2015
|
#
?
Jan 31, 2015 15:54
|
|
- New Yorp New Yorp
- Jul 18, 2003
-
Only in Kenya.
-
Pillbug
|
The "IIS" part is a name for the action. This lets you do things like:
code:WindowsFeature NET45
{
Ensure = "present"
Name = "AS-NET-Framework"
}
WindowsFeature IIS
{
Ensure = "present"
Name = "Web-Server"
DependsOn = "[WindowsFeature]NET45"
}
Get-WindowsFeature is going to be the easiest way to find the names of all the features.
And you'll probably want something from the DSC resource kit before too long, so here it is:
https://gallery.technet.microsoft.com/scriptcenter/DSC-Resource-Kit-All-c449312d
|
#
?
Jan 31, 2015 16:10
|
|
- Dr. Arbitrary
- Mar 15, 2006
-
-
Bleak Gremlin
|
So, is NET45 something that is explicitly defined somewhere or is that a name that you just decided would be a good description for the part in the braces?
Edit:
I found what I need:
https://technet.microsoft.com/en-us/library/dn282127.aspx
Dr. Arbitrary fucked around with this message at 16:55 on Jan 31, 2015
|
#
?
Jan 31, 2015 16:44
|
|
- Briantist
- Dec 5, 2003
-
The Professor does not approve of your post.
-
Lipstick Apathy
|
NET45 is an arbitrary name that you choose. The feature name you put in the "Name = " part is explicitly defined (as Ithaqua pointed out, Get-WindowsFeature is the best way to see those).
DSC is pretty cool. I've deployed a pull server, used secure credentials in configs, written custom resources, etc. There are definitely quirks and things that are confusing about how to use it. Are you starting with a Push configuration (where you just apply the config manually to a node)? That's a good way to start off with the declaritive syntax before adding in the complexities of a Pull server.
|
#
?
Jan 31, 2015 20:10
|
|
- Dr. Arbitrary
- Mar 15, 2006
-
-
Bleak Gremlin
|
NET45 is an arbitrary name that you choose. The feature name you put in the "Name = " part is explicitly defined (as Ithaqua pointed out, Get-WindowsFeature is the best way to see those).
DSC is pretty cool. I've deployed a pull server, used secure credentials in configs, written custom resources, etc. There are definitely quirks and things that are confusing about how to use it. Are you starting with a Push configuration (where you just apply the config manually to a node)? That's a good way to start off with the declaritive syntax before adding in the complexities of a Pull server.
I think I've got it under control now:
I made two configs, switching the Present and Absent switches:
code:Configuration Lab2
{
LocalConfigurationManager
{
RebootNodeIfNeeded = $true
}
Node "ServerB"
{
WindowsFeature PrintSvc
{
Ensure = "Present"
Name = "Print-Services"
}
WindowsFeature InstallIIIS
{
Ensure = "Present"
Name = "Web-Server"
}
WindowsFeature GroupPolicyManagement
{
Ensure = "Present"
Name = "GPMC"
}
WindowsFeature GUI
{
Ensure = "Absent"
Name = "User-Interface-Infra"
}
WindowsFeature GUIShell
{
Ensure = "Present"
Name = "Server-Gui-Shell"
}
}
}
It actually worked!
Not sure how to move from here to a push or pull server but I think I've gotten over the initial hump.
|
#
?
Jan 31, 2015 21:01
|
|
- Briantist
- Dec 5, 2003
-
The Professor does not approve of your post.
-
Lipstick Apathy
|
I think I've got it under control now:
I made two configs, switching the Present and Absent switches:
It actually worked!
Not sure how to move from here to a push or pull server but I think I've gotten over the initial hump.
Nice! Push mode is when you use Start-DscConfiguration to apply the config; you don't use a separate server with it. That's likely what you're doing now.
Also, you can have the LocalConfigurationManager section in the same config, but you don't have to. I mean either way, you're going to have a different config for the LCM vs the Node (when you execute this config you're going to get 2 MOF files), so you can configure the LCM in a separate file if you prefer. When put in the same file, one has no effect on the other.
|
#
?
Jan 31, 2015 22:47
|
|
- ConfusedUs
- Feb 24, 2004
-
Bees?
You want fucking bees?
Here you go!
ROLL INITIATIVE!!
|
I have a little project I want to put together.
I'm not very good at programming and powershell, but I think I can do this. Before I get into the nitty-gritty details, I want to kind of break it down into pieces and see if I'm missing anything obvious.
Here's the general idea:
I have an application that runs jobs on a schedule. Every job can have one of three statuses: success, failure, or warning. Failures and warnings always log some kind of error code as to what went wrong. For example, if access was denied, you might get ACCESS_DENIED. All of these are logged in a database.
I want to run a script that will trawl through jobs since <date>, pull out the Failures and Warnings, dump the details to a html file, and provide links to knowledgebase articles about each of these states so that users can self-troubleshoot.
(Or so our less competent support guys can at least start on the right foot)
I already know how to pull the info from the database. We do this already for other stuff, and I can just crib from that. I also have a list of which KB links correspond to which codes.
So I can pull the info and dump it to a file. That's not hard.
This is where I get a bit fuzzy. Should I dump it to a CSV file, compare with my list, and add a "links" column; once that's done, I could output to a HTML table or something.
Or should I do something else? Anyone have general advice?
|
#
?
Feb 5, 2015 18:02
|
|
- myron cope
- Apr 21, 2009
-
|
Here's a probably dumb question.
I have a script that creates text files. In this example, there are 3 files. I want to merge them into 1 file, but only if the same text is in all 3 files. If it's not in all 3, it can just be discarded.
I'm doing code:Get-Content "file-*.txt" | Sort-Object -Unique
But now that I'm actually looking at it, it's just combining all 3 of them and then keeping only 1 instance of the text--not searching to see if the same text is in all 3. (It's working as it should, I just didn't realize what it was doing at first)
The text is mostly random IP addresses.
|
#
?
Feb 5, 2015 18:40
|
|
- FISHMANPET
- Mar 3, 2007
-
Sweet 'N Sour
Can't
Melt
Steel Beams
|
What about something like this?
I took out -AsJob.
You're already returning an object which is good, and it already has an error property, even better.
As you pointed out, you can't throw an exception on the remote side and catch it on the local side. That's because it's a completely different session or runspace. Any objects sent back are serialized and so are no longer "live".
So I changed the code a bit so that when there is no error, it just sets the error property in your object to $null. When there is an exception, just use $_ and don't bother with the internal exception's message (right now we just want to pass this back to the caller).
Then back on the calling side, you check for an error in the property. At this point, you could JUST use this method (an if statement) instead of try/catch, but I'm assuming you want to use try/catch so if the error exists, then we just throw the error as is (which you can then catch and handle as necessary).
I haven't tested this yet, but it's fairly workable and much easier than using jobs.
Jobs give the added benefit of asynchronous-ness but your code as is could easily fail if the remote job were not yet completed. So you'd need more code to check on the status of the jobs that are waiting and receive the results when necessary.
So I put this aside for a few days, and came back to it on Monday. The reason I was using -AsJob was that I was trying to catch the case where invoke-command couldn't connect to the machine for whatever reason. But after letting it sit for a while and coming back, I decided to add "-ErrorAction Stop" to the Invoke-Command so now it stops and properly throws an error when it can't connect.
|
#
?
Feb 5, 2015 18:47
|
|
- ElGroucho
- Nov 1, 2005
-
We already - What about sticking our middle fingers up... That was insane
-
Fun Shoe
|
Here's a probably dumb question.
I have a script that creates text files. In this example, there are 3 files. I want to merge them into 1 file, but only if the same text is in all 3 files. If it's not in all 3, it can just be discarded.
I'm doing code:Get-Content "file-*.txt" | Sort-Object -Unique
But now that I'm actually looking at it, it's just combining all 3 of them and then keeping only 1 instance of the text--not searching to see if the same text is in all 3. (It's working as it should, I just didn't realize what it was doing at first)
The text is mostly random IP addresses.
I wish I could say "Do it in Python" without sounding like an rear end in a top hat
|
#
?
Feb 5, 2015 18:50
|
|
- myron cope
- Apr 21, 2009
-
|
I wish I could say "Do it in Python" without sounding like an rear end in a top hat
Yeah I'm sure Powershell is not the greatest for this. But I know a little of Powershell and none of Python. Maybe I'll look into python though anyway.
|
#
?
Feb 5, 2015 18:52
|
|
- ElGroucho
- Nov 1, 2005
-
We already - What about sticking our middle fingers up... That was insane
-
Fun Shoe
|
Should work in python 2 & 3, hope it gives you a start
code:def make_dict(fin):
new_dict = dict() # Dictionaries search crazy fast
for line in fin:
ip = line.rstrip() # strips new line character
new_dict[ip] = 0 # Creates key ip; Value doesn't matter
return new_dict
def main():
fin1 = open('file1.txt', 'r')
fin2 = open('file2.txt', 'r')
fin3 = open('file3.txt', 'r')
file1 = make_dict(fin1)
file2 = make_dict(fin2)
file3 = make_dict(fin3)
outfile = open('output.txt', 'w')
for ip in file1:
if (ip in file2) and (ip in file3):
outfile.write(ip + '\n')
fin1.close()
fin2.close()
fin3.close()
outfile.close()
main()
|
#
?
Feb 5, 2015 19:15
|
|
- Adbot
-
ADBOT LOVES YOU
|
|
#
?
May 15, 2024 03:54
|
|
- myron cope
- Apr 21, 2009
-
|
I think python (or something that isn't powershell, at least) is ultimately a better option, but I need to, you know, learn some python first.
So in the mean time, I've settled on this horrid workaround:
code:Compare-Object (gc "file1.txt") (gc "file2.txt") -PassThru -IncludeEqual | Where-Object { $_.SideIndicator -eq '==' } | Sort-Object
Which seems to work. It would seem -ExcludeDifferent would be what I want but it never had any output (that I could pipe at least) and I can't figure out why.
If it's not abundantly clear, I basically hacked this together without really knowing more than the basics of powershell just from searching online
|
#
?
Feb 6, 2015 02:14
|
|