Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Pile Of Garbage
May 28, 2007



Briantist posted:

Yeah modules are the way to go. Ensure they are well-formed modules with proper paths and manifests and then put them in a path that's included in variable cheese-cube mentioned, that way you can import them by name only.

Sure, being able to import modules by name instead of path is nice but I was more talking about the implicit importing feature introduced in PowerShell 3.0 which loads modules automatically meaning that you don't have to call Import-Module. As long as your module shows up in the output of Get-Module -ListAvailable it can be automatically imported. Outside of scripting this feature is especially useful if you do a lot of administration and whatnot via the CLI.

Adbot
ADBOT LOVES YOU

Inspector_666
Oct 7, 2003

benny with the good hair

Briantist posted:

Yeah modules are the way to go. Ensure they are well-formed modules with proper paths and manifests and then put them in a path that's included in variable cheese-cube mentioned, that way you can import them by name only.

I started separating out every function into its own .ps1 file (that matches the function name) for my modules, in folders that determine whether they get exported or not (like Public and Pivate). Then my .psm1 becomes boilerplate code like this:

code:
#Requires -Version 4.0

$Subs = @(
    @{
        Path = 'Private'
        Export = $false
        Recurse = $false
    } ,

    @{
        Path = 'Public'
        Export = $true
        Recurse = $true
    }
) 

$Subs | ForEach-Object -Process {
    $sub = $_
    $PSScriptRoot | Join-Path -ChildPath $sub.Path | 
    Get-ChildItem -Filter *-*.ps1 -Recurse:$sub.Recurse -ErrorAction Ignore | ForEach-Object -Process {
        try {
            . $_.FullName
            if ($sub.Export -or $Global:__MyModuleName_Export_All) {
                Export-ModuleMember -Function $_.BaseName
            }
        } catch {
            Write-Error -Message "Could not import $($_.FullName)"
        }
    }
}

Oh dag, that's cool as hell. I'm definitely going to look into breaking the existing scripts down into future modularity like this.

I'll probably also have to dive into the manifest files for my new hire script since it involves a lot of csv lookups and exporting stuff, and there's currently a lot of $PSScriptRoot scattered around a couple of other ones.

Inspector_666 fucked around with this message at 19:39 on Feb 16, 2017

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

cheese-cube posted:

Sure, being able to import modules by name instead of path is nice but I was more talking about the implicit importing feature introduced in PowerShell 3.0 which loads modules automatically meaning that you don't have to call Import-Module. As long as your module shows up in the output of Get-Module -ListAvailable it can be automatically imported. Outside of scripting this feature is especially useful if you do a lot of administration and whatnot via the CLI.
It's not just that it's nice, it ensures that the manifest is loaded, rather than calling the PSD1 directly; it's a consistent name. Additionally, the automatic module import doesn't work unless your module is well-formed.

It's definitely useful in the CLI; I never rely on it in scripts.

Pile Of Garbage
May 28, 2007



Briantist posted:

It's definitely useful in the CLI; I never rely on it in scripts.

Agreedo 100%. I always explicitly load modules in scripts and include exception handling to ensure that they do actually load.

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

cheese-cube posted:

Agreedo 100%. I always explicitly load modules in scripts and include exception handling to ensure that they do actually load.
Do you do a whole try {} catch {} around it?

I either use #Requires -Module or Import-Module Module -ErrorAction Stop and leave it at that.

Inspector_666
Oct 7, 2003

benny with the good hair

Briantist posted:

Do you do a whole try {} catch {} around it?

I either use #Requires -Module or Import-Module Module -ErrorAction Stop and leave it at that.

Doesn't #Requires always stop the script if it fails? Seems like anything else would kind of defeat the purpose.

Pile Of Garbage
May 28, 2007



Briantist posted:

Do you do a whole try {} catch {} around it?

I either use #Requires -Module or Import-Module Module -ErrorAction Stop and leave it at that.

Wow OK so I'll sheepishly admit that I've never known about #Requires statements in PS however I'll definitely be using from now on. It's true, you learn something new everyday!

Previously I've just been using try {} catch {} around Import-Module, primarily because I write scripts which are meant to run unattended so I need to catch exceptions and write them out to a log file before throwing them.

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

Inspector_666 posted:

Doesn't #Requires always stop the script if it fails? Seems like anything else would kind of defeat the purpose.
Yes, that's why I usually use that (in place of Import-Module). I'll use ipmo if it must run under PowerShell v2.

cheese-cube posted:

Wow OK so I'll sheepishly admit that I've never known about #Requires statements in PS however I'll definitely be using from now on. It's true, you learn something new everyday!

Previously I've just been using try {} catch {} around Import-Module, primarily because I write scripts which are meant to run unattended so I need to catch exceptions and write them out to a log file before throwing them.
They're nice but I think you need v3+ to reliably use it with -Modules.

I've seen people do try/catch around Import-Module but I figure if your script has to exit anyway, why not just let it terminate? I guess the log file scenario is one reason, though these days I've set up automatic transcription through group policy so I tend to avoid writing logs manually (that really needs v5 to work well though).

But yeah as Inspector_666 said, #Requires will prevent the script from executing so don't use if for your use case unless you don't need to log those errors.

Pile Of Garbage
May 28, 2007



Briantist posted:

I guess the log file scenario is one reason, though these days I've set up automatic transcription through group policy so I tend to avoid writing logs manually (that really needs v5 to work well though).

The majority of exceptions don't really provide much info to go on so I like to write $Error[0] plus some context to the log file.

Regarding WMF 5.0 as I mentioned earlier in the thread there's a lot of stuff that has been deemed incompatible with WMF 5.0 (https://msdn.microsoft.com/en-us/powershell/wmf/5.0/productincompat) so you're pretty much stuck with 4.0 unless you're in a green-fields latest and greatest environment.

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

cheese-cube posted:

Regarding WMF 5.0 as I mentioned earlier in the thread there's a lot of stuff that has been deemed incompatible with WMF 5.0 (https://msdn.microsoft.com/en-us/powershell/wmf/5.0/productincompat) so you're pretty much stuck with 4.0 unless you're in a green-fields latest and greatest environment.
It's definitelt good to be aware of these things, but I wouldn't call that a lot of stuff; it's a small, specific list. It's the usual lovely products: Exchange, System Center, Lync/S4B, SharePoint.

WMF 5.1 is out but it doesn't seem to have such a list.

I don't at all run in a greenfield environment but the vast majority of our servers can use 5/5.1. I think it's just Lync/Skype servers that we're not upgrading it on so we mostly get the benefits.

YMMV of course.

Also if you run a script from a 5+ machine that remotes into an earlier machine to do work there, the output still comes back to the calling session and would get logged.

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.
I'm trying to add content to a file, but am hitting a snag with my "-join"ed content being split into new lines at the join points. Eg:

code:
$fileLocation = someFunction('someInput') # works fine
$newContent = (-Join "`r`nThis content should ", "all be on ", "one line") # outputs correctly with, say, write-host

Add-Content $fileLocation $newContent
adds

code:
This content should 
all be on 
one line
to my file.

Advice?

nielsm
Jun 1, 2009



No idea about that, but I've always just used the + operator to assemble strings when needed. Or string interpolation to glue contents of variables into strings.

code:
"abc" + "def"
"Free space: $spaceFree GB"

PBS
Sep 21, 2015

Newf posted:

I'm trying to add content to a file, but am hitting a snag with my "-join"ed content being split into new lines at the join points. Eg:

code:
$fileLocation = someFunction('someInput') # works fine
$newContent = (-Join "`r`nThis content should ", "all be on ", "one line") # outputs correctly with, say, write-host

Add-Content $fileLocation $newContent
adds

code:
This content should 
all be on 
one line
to my file.

Advice?

Needs to be in parenthesis.

code:
$newContent = -Join ("`r`nThis content should ", "all be on ", "one line")

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

nielsm posted:

No idea about that, but I've always just used the + operator to assemble strings when needed. Or string interpolation to glue contents of variables into strings.

code:
"abc" + "def"
"Free space: $spaceFree GB"
Yeah, I would definitely leave out the -Join operator
code:
$fileLocation = someFunction('someInput') # works fine
$newContent = "`r`nThis content should " + "all be on " + "one line"

Add-Content $fileLocation $newContent

PBS
Sep 21, 2015

anthonypants posted:

Yeah, I would definitely leave out the -Join operator
code:
$fileLocation = someFunction('someInput') # works fine
$newContent = "`r`nThis content should " + "all be on " + "one line"

Add-Content $fileLocation $newContent

Depends on what he's doing, in the example it doesn't matter, but if he's actually trying to join something more complex with a delimiter he needs it.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

PBS posted:

Depends on what he's doing, in the example it doesn't matter, but if he's actually trying to join stuff with a delimiter he needs it.
Then they should include more details or else they're going to get X/Y'd to death

Newf
Feb 14, 2006
I appreciate hacky sack on a much deeper level than you.
Thanks all. I'm forever misplacing parenthesis in PS.

The Claptain
May 11, 2014

Grimey Drawer
I am trying to update ProxyAddresses attribute on multiple AD users. The idea is, if user has default Proxy Address set (denoted by uppercase SMTP:) add new one as an alias (with lowercase smtp:), and if ProxxyAddresses is not set, or in lowercase, add it in uppercase. This is what I have so far:

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
		if ($_.ProxyAddresses -cmatch "SMTP")
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "smtp:$($_.UserPrincipalName)"}
		}
		else
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "SMTP:$($_.UserPrincipalName)"}
		}
	}
I doesn't work as expected. If the proxy address is not set, it sets it as expected, matching UPN. If there is a proxy address matching upn, lower or upper case, the attribute remains unmodified. And if there is a proxy address not matching UPN, new one is added in uppercase.

I must be missing something painfully obvious, but I can't find out what.

PBS
Sep 21, 2015
For starters, try changing to clike instead. I don't really see any glaring issues. My guess is you're using match incorrectly, match uses regex. I've never really taken the time to figure out match, but it is generally faster than like.

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
		if ($_.ProxyAddresses -clike "*SMTP*")
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "smtp:$($_.UserPrincipalName)"}
		}
		else
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "SMTP:$($_.UserPrincipalName)"}
		}
	}
You could try -cmatch 'SMTP.*' too if you want to stick with match.

Tip, use regexr to test your regex.

PBS fucked around with this message at 16:24 on Mar 10, 2017

The Claptain
May 11, 2014

Grimey Drawer

PBS posted:

For starters, try changing to clike instead. I don't really see any glaring issues. My guess is you're using match incorrectly, match uses regex. I've never really taken the time to figure out match, but it is generally faster than like.

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
		if ($_.ProxyAddresses -clike "*SMTP*")
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "smtp:$($_.UserPrincipalName)"}
		}
		else
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "SMTP:$($_.UserPrincipalName)"}
		}
	}
You could try -cmatch 'SMTP.*' too if you want to stick with match.

Tip, use regexr to test your regex.

Match will return $true if a value is found anywhere in the string. I tested the output of cmatch, and it returns the correct values.

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

The Claptain posted:

I am trying to update ProxyAddresses attribute on multiple AD users. The idea is, if user has default Proxy Address set (denoted by uppercase SMTP:) add new one as an alias (with lowercase smtp:), and if ProxxyAddresses is not set, or in lowercase, add it in uppercase. This is what I have so far:

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
		if ($_.ProxyAddresses -cmatch "SMTP")
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "smtp:$($_.UserPrincipalName)"}
		}
		else
		{
			Set-ADUser $_ -Add @{ProxyAddresses = "SMTP:$($_.UserPrincipalName)"}
		}
	}
I doesn't work as expected. If the proxy address is not set, it sets it as expected, matching UPN. If there is a proxy address matching upn, lower or upper case, the attribute remains unmodified. And if there is a proxy address not matching UPN, new one is added in uppercase.

I must be missing something painfully obvious, but I can't find out what.

ProxyAddresses is multi-valued (it's an array). -Add adds an attribute to the AD object, but it won't add a value to a multi-valued attribute. The attributes value itself must be complete, so you will have to create / modify the array itself in code before passing it to Set-ADUser.

This also means that your check is not quite doing what you think, but it will still work (mostly). When you use the -match or -like (or most) operators with the left side being an array, instead of returning a boolean value it returns an array containing the items that match.

In your case this kind of works, since if there are no entries that match the pattern the result will be an empty array, which will evaluate to false, and an array of any size will evaluate to true. The thing where you have to be careful with that pattern is that it looks for SMTP anywhere in the string it searches.

Consider a proxy address like this: smtp:IheartSMTP@example.com

That will match your pattern. Instead, anchor it at the beginning of the string using ^SMTP:.

Once you've done that, you'll have to (re)construct the addresses array before setting it on the object, at which point you need to use the -Replace operator rather than -Add:

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
                $current = $_.ProxyAddresses
		if ($current -cmatch "^SMTP:")
		{
                        $current += "smtp:$($_.UserPrincipalName)"
			Set-ADUser $_ -Replace @{ProxyAddresses = $current }
		}
		else
		{
                        $current += "SMTP:$($_.UserPrincipalName)"
			Set-ADUser $_ -Replace @{ProxyAddresses = $current}
		}
	}
This can be refactored even more to eliminate the duplicate Set-ADUser calls and similar $current modifications, but I'll leave that an exercise for you.

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum
Hey, I did this a while back and posted about it

anthonypants posted:

I wrote a script to rename our userPrincipalName and proxyAddresses because we use .local as our tld for everything and we need to move to Office 365. Most of the scripts I found were "just replace the proxyAddresses with 'smtp:samaccountname@domain.tld'!" but a lot of people have alternate email addresses or have changed their last names, so I came up with this monstrosity to just do a find/replace inside of everything instead. I'm probably still reinventing the wheel here, but whatever.
code:
$ou = "OU=Organizational Unit,DC=domain,DC=tld"
foreach ($u in Get-ADUser -SearchBase $ou -Filter * -Properties userPrincipalName,proxyAddresses | Where-Object {$_.proxyAddresses[0] -ne $null}) {
    $upn = $u.userPrincipalName -replace "local","net"
    Set-ADUser $u -UserPrincipalName $upn
    $prx = $null
    foreach ($p in Get-ADUser $u -Properties proxyAddresses | Select-Object -ExpandProperty proxyAddresses) {
        $p = $p -replace ".local$",".net"
        if (($p -clike "smtp:*") -and ($p -like "*$($u.SamAccountName)*net")) {
            $p = $p -replace '^smtp:','SMTP:'
        } else {
            $p = $p -creplace '^SMTP:','smtp:'
        }
        if ($prx -notcontains $p) {
            $prx += @($p)
        }
    }
    Set-ADUser $u -Replace @{proxyAddresses=$prx}
}
e: sometimes the samaccountname or the proxyaddresses don't have matching upper/lowercase so it can't be in the -clike statement or else nothing gets
ee: also the last creplace should replace uppercase, and add carets and colons to all the replacement strings to make sure it doesn't throw off anything else, like X400 addresses
eee: should probably do that with replacing the upn, too

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

anthonypants posted:

e: sometimes the samaccountname or the proxyaddresses don't have matching upper/lowercase so it can't be in the -clike statement or else nothing gets
ee: also the last creplace should replace uppercase, and add carets and colons to all the replacement strings to make sure it doesn't throw off anything else, like X400 addresses
eee: should probably do that with replacing the upn, too
If you use -match (even the C or I versions), you can make part of the regex case insensitive (or sensitive), by using flags inside the regex, if you must do it in one match. But I think it's clearer to do 2 compares like you're doing.

See Demo: ^SMTP:(?i)EmaiLaDDreSS

anthonypants
May 6, 2007

by Nyc_Tattoo
Dinosaur Gum

Briantist posted:

If you use -match (even the C or I versions), you can make part of the regex case insensitive (or sensitive), by using flags inside the regex, if you must do it in one match. But I think it's clearer to do 2 compares like you're doing.

See Demo: ^SMTP:(?i)EmaiLaDDreSS
I like being clear, and I think it's important, which is one of the reasons why I try to match capitalization and type out all the cmdlet names instead of using aliases.

Briantist
Dec 5, 2003

The Professor does not approve of your post.
Lipstick Apathy

anthonypants posted:

I like being clear, and I think it's important, which is one of the reasons why I try to match capitalization and type out all the cmdlet names instead of using aliases.
I'm 100% in agreement; I do the same.

I was just pointing it out because that feature of regex is not as well known, and in other situations doing 2 matches is not the same.

The Claptain
May 11, 2014

Grimey Drawer

Briantist posted:

ProxyAddresses is multi-valued (it's an array). -Add adds an attribute to the AD object, but it won't add a value to a multi-valued attribute. The attributes value itself must be complete, so you will have to create / modify the array itself in code before passing it to Set-ADUser.

I thought I was doing something wrong with regards to multi-valued attribute, and not with the rest of the script.

[/quote]This also means that your check is not quite doing what you think, but it will still work (mostly). When you use the -match or -like (or most) operators with the left side being an array, instead of returning a boolean value it returns an array containing the items that match.

In your case this kind of works, since if there are no entries that match the pattern the result will be an empty array, which will evaluate to false, and an array of any size will evaluate to true. The thing where you have to be careful with that pattern is that it looks for SMTP anywhere in the string it searches.

Consider a proxy address like this: smtp:IheartSMTP@example.com

That will match your pattern. Instead, anchor it at the beginning of the string using ^SMTP:.[/quote]

I was aware of this, but left it aside "I'll whink about it when I get the rest of the script working".

quote:

Once you've done that, you'll have to (re)construct the addresses array before setting it on the object, at which point you need to use the -Replace operator rather than -Add:

code:
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties * |
	ForEach-Object{
                $current = $_.ProxyAddresses
		if ($current -cmatch "^SMTP:")
		{
                        $current += "smtp:$($_.UserPrincipalName)"
			Set-ADUser $_ -Replace @{ProxyAddresses = $current }
		}
		else
		{
                        $current += "SMTP:$($_.UserPrincipalName)"
			Set-ADUser $_ -Replace @{ProxyAddresses = $current}
		}
	}

Unfortunately, this throws out an exception:
code:
Set-ADUser : The specified value already exists
At line:7 char:4
+             Set-ADUser $_ -Replace @{ProxyAddresses = $current }
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (CN=1,OU=Test,DC=fried,DC=tv:ADUser) [Set-ADUser], ADException
    + FullyQualifiedErrorId : ActiveDirectoryServer:8323,Microsoft.ActiveDirectory.Management.Commands.SetADUser
I thought that maybe I should use the creplace parameter instead of the replace, but I get "Parameter cannot be found" error.

e: Nevermind, I'm dumb and this works perfectly. I was trying to add the same proxy address. Don't script without morning coffee.

Thanks for the help!

anthonypants posted:

Hey, I did this a while back and posted about it

I should have searched the thread more, so thank you, too.

The Claptain fucked around with this message at 10:03 on Mar 13, 2017

Pile Of Garbage
May 28, 2007



anthonypants posted:

I like being clear, and I think it's important, which is one of the reasons why I try to match capitalization and type out all the cmdlet names instead of using aliases.

:same:

Using full cmdlet names and parameter values will cost you nothing and often times save you debugging.

Edit: re this SMTP proxy address malarkey, pretty sure there's a native EMS cmdlet for managing addresses.

nielsm
Jun 1, 2009



I can't remember the terms to search for here, so can't find an answer...

I have a bunch of WMI objects I want to pass to Remove-WmiObject -Confirm, but the identity displayed for each is useless to the operator. Is there a way to override the "short display string" or whatever it's called for an object?

code:
$profiles = Get-WmiObject -Class Win32_UserProfile -ComputerName $target
# filter $profiles here
$profiles | Remove-WmiObject -Confirm
Gives a confirmation prompt like this:
pre:
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove-WmiObject" on target "\\machine\root\cimv2:Win32_UserProfile.SID="S-1-5-18"".
Which is rather useless for identifying what is actually affected. (This example is the local system account, should probably not delete.) I'd rather display the LocalPath property or a custom NoteProperty of the object.

PBS
Sep 21, 2015

nielsm posted:

I can't remember the terms to search for here, so can't find an answer...

I have a bunch of WMI objects I want to pass to Remove-WmiObject -Confirm, but the identity displayed for each is useless to the operator. Is there a way to override the "short display string" or whatever it's called for an object?

code:
$profiles = Get-WmiObject -Class Win32_UserProfile -ComputerName $target
# filter $profiles here
$profiles | Remove-WmiObject -Confirm
Gives a confirmation prompt like this:
pre:
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove-WmiObject" on target "\\machine\root\cimv2:Win32_UserProfile.SID="S-1-5-18"".
Which is rather useless for identifying what is actually affected. (This example is the local system account, should probably not delete.) I'd rather display the LocalPath property or a custom NoteProperty of the object.

That output is the result of what is being passed to the method used for confirmation. Without changing the target yourself, I don't think you can change what's displayed for the confirmation without modifying those cmdlettes.

The easiest solution is probably to iterate though the objects and write information about the object before the confirmation dialog appears.

nielsm
Jun 1, 2009



PBS posted:

That output is the result of what is being passed to the method used for confirmation. Without changing the target yourself, I don't think you can change what's displayed for the confirmation without modifying those cmdlettes.

The easiest solution is probably to iterate though the objects and write information about the object before the confirmation dialog appears.

I think it uses obj.ToString() to get the identity shown, but really no idea. I'm not sure if it's even documented.
The problem with manually iterating over the objects is that you can very easily break "Yes to All" and "No to All" which are important to have in this use case.

But I think maybe writing a cmdlet of my own that just wraps Remove-WmiObject but somehow causes a more useful object identity to be printed, could work.

PBS
Sep 21, 2015

nielsm posted:

I think it uses obj.ToString() to get the identity shown, but really no idea. I'm not sure if it's even documented.
The problem with manually iterating over the objects is that you can very easily break "Yes to All" and "No to All" which are important to have in this use case.

But I think maybe writing a cmdlet of my own that just wraps Remove-WmiObject but somehow causes a more useful object identity to be printed, could work.

True, but if you're worried about deleting a system account or something why would you want to select yes to all, and if you do want to why even bother with -confirm?

code:
try
        {
          if (!this.ShouldProcess(this.inputObject["__PATH"].ToString()))
            return;
          this.inputObject.Delete();
        }
That's part of the underlying code for that commandlet, so it's taking __PATH from the object and doing ToString instead of the entire object. Makes a bit more sense that it'd be doing it that way.

AAAAA! Real Muenster
Jul 12, 2008

My QB is also named Bort

Hello gentlegoons, I just got referred to this thread as someone who is looking to expand on my use of AutoHotKey with a more powerful tool. I've read through the op and noticed that most of Adaz's examples (from 2010) look to be regarding running scripts to do things on a server or on the administrative side of IT work. I work on a support desk at a software engineering company and do a number of repetitive tasks in Salesforce and in our proprietary software. I have used AHK to make ~40+ scripts to automate my most common/most repetitive work in Salesforce, but I dont feel like AHK is robust enough to what I would want it to do on the front-end of the software I support - is Powershell something I should be looking into? Or am I a bad that needs to learn more about AHK?

On a side, but related note, I am making a push to join development at my company as a QA, and one of the goals on that side is to try to start to automate some of the QA processes, and I figure knowing something more advanced than AHK would be wise - can Powershell automate clicking through webpages and completing actions in a website? Can it be programmed to be intuitive at all, such as with something akin to if/then statements?

AAAAA! Real Muenster fucked around with this message at 14:24 on Mar 23, 2017

Pile Of Garbage
May 28, 2007



I had to Google it but I presume AHK = AutoHotKey? I wouldn't recommend using PowerShell to do simulated transactional stuff like you're already doing with AHK. I've never used Salesforce personally but it seems strange that you're using AHK with it for the purpose of automation. Surely they have an API that you can hook into?

Regarding your last question, PowerShell is a functional language so control structures like if/else are fully supported.

AAAAA! Real Muenster
Jul 12, 2008

My QB is also named Bort

cheese-cube posted:

I had to Google it but I presume AHK = AutoHotKey? I wouldn't recommend using PowerShell to do simulated transactional stuff like you're already doing with AHK. I've never used Salesforce personally but it seems strange that you're using AHK with it for the purpose of automation. Surely they have an API that you can hook into?

Regarding your last question, PowerShell is a functional language so control structures like if/else are fully supported.
Hah, yeah, I should have spelled that out, it is AutoHotKey, sorry about that. I use it because many of the cases I work in Salesforce are repetitive and 1) I'm lazy 2) I was getting carpel tunnel manually entering up to two dozen clicks/interactions I do on each of the 50+ cases I have to work in a day. It is mostly just data entry into fields that either require input in each case, or the fields default to the wrong thing because we have not had a Salesforce admin in over 2 years. I taught myself AHK one weekend and now I am the highest case closer on my team and spend all this newfound free time doing Useful Things, like becoming the leading expert in the company about our really broken and lovely product (despite being a level 1 :haw: ), playing Ping Pong, and reading threads on SA.

I dont have much tech background or training before I got this job (I dont have a college degree), so working with an API or more advanced scripts is beyond my knowledge at this point, but I am obviously trying to learn and do more.

Pile Of Garbage
May 28, 2007



AAAAA! Real Muenster posted:

Hah, yeah, I should have spelled that out, it is AutoHotKey, sorry about that. I use it because many of the cases I work in Salesforce are repetitive and 1) I'm lazy 2) I was getting carpel tunnel manually entering up to two dozen clicks/interactions I do on each of the 50+ cases I have to work in a day. It is mostly just data entry into fields that either require input in each case, or the fields default to the wrong thing because we have not had a Salesforce admin in over 2 years. I taught myself AHK one weekend and now I am the highest case closer on my team and spend all this newfound free time doing Useful Things, like becoming the leading expert in the company about our really broken and lovely product (despite being a level 1 :haw: ), playing Ping Pong, and reading threads on SA.

I dont have much tech background or training before I got this job (I dont have a college degree), so working with an API or more advanced scripts is beyond my knowledge at this point, but I am obviously trying to learn and do more.

From the sound of it you're already smashing things by taking advantage of AHK so I reckon the next step is to learn a programming language which will allow you to interface with Salesforce directly using their APIs. As I said before I have zero experience with Salesforce however it looks like they have multiple APIs available. This means you could probably learn any language and then use that effectively with the product. PowerShell is an option here however it's not exactly designed for this kind of work and I suspect that other languages have libraries available which make things much easier. As to choosing a language I can't really comment as I pretty much only work with PS and .NET. Maybe someone else can point you in the right direction.

PBS
Sep 21, 2015

cheese-cube posted:

From the sound of it you're already smashing things by taking advantage of AHK so I reckon the next step is to learn a programming language which will allow you to interface with Salesforce directly using their APIs. As I said before I have zero experience with Salesforce however it looks like they have multiple APIs available. This means you could probably learn any language and then use that effectively with the product. PowerShell is an option here however it's not exactly designed for this kind of work and I suspect that other languages have libraries available which make things much easier. As to choosing a language I can't really comment as I pretty much only work with PS and .NET. Maybe someone else can point you in the right direction.

Powershell's webserviceproxy is top notch, would probably work pretty well for this. It's not a good choice if the service descriptions are hidden behind an authentication scheme though.

thebigcow
Jan 3, 2001

Bully!
https://www.jbmurphy.com/2016/07/25/connecting-to-the-salesforce-rest-api-using-powershell/

I'd bet a lot of your problems have already been figured out, just stick "Salesforce PowerShell" into your search engine of choice. I'd also bet none of it looks like very clean PowerShell so it's going to be a hard thing to start with.

edit: Don't get too discouraged. These things are worth learning in general, and you've already experienced the joy of turning a monotonous data manipulation task into a script that you just run while you get coffee and waste your employers time.

thebigcow fucked around with this message at 18:13 on Mar 23, 2017

AAAAA! Real Muenster
Jul 12, 2008

My QB is also named Bort

thebigcow posted:

https://www.jbmurphy.com/2016/07/25/connecting-to-the-salesforce-rest-api-using-powershell/

I'd bet a lot of your problems have already been figured out, just stick "Salesforce PowerShell" into your search engine of choice. I'd also bet none of it looks like very clean PowerShell so it's going to be a hard thing to start with.

edit: Don't get too discouraged. These things are worth learning in general, and you've already experienced the joy of turning a monotonous data manipulation task into a script that you just run while you get coffee and waste your employers time.
Oh I'm not discouraged because I do want to learn it either way, it sounds like a good thing to have in my back pocket and on my resume. It seems I didnt word my earlier posts very well, because I want a tool that will let me manipulate moving about our proprietary software application that I access through a web browser, rather than necessarily doing more with Salesforce.

I am, as cheese_cube so aptly put it, smashing things in Salesforce already, so that issue is essentially tackled, though I wouldnt mind upping my game even more, so my concern is getting some automation for the tasks I do in the proprietary software, which is not as manipulatable with AutoHotKey (to my knowledge).


I think the biggest thing stopping me on our software when it comes to AHK is the issue of pages taking time to load - if salesforce starts its script before the page loads its hosed from the start and I have to wait for it to finish thrashing about before I can try again. And writing a separate script for each page would take too many keys.

skipdogg
Nov 29, 2004
Resident SRT-4 Expert

Powershell can do a lot, but I'd start looking at different tools.

Check out Selenium for the web browser stuff

http://www.seleniumhq.org/

Adbot
ADBOT LOVES YOU

Dr. Arbitrary
Mar 15, 2006

Bleak Gremlin
I've automated some web stuff with Powershell, but it was all stuff like
Press tab two times, fill in field, press tab four times, fill in field, and so on.

Other tools that make it easier are probably what you want.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply