poshbotio / PoshBot

Powershell-based bot framework
MIT License
540 stars 108 forks source link

Feature Request: Startup Script for configurations. #65

Closed shotah closed 7 years ago

shotah commented 7 years ago

Startup Script: Trying to push this through a CI and would like to set psrepo in some sort of startup script in my New-PoshBotScheduledTask. Also, I had to add are reboot to the CI task to make poshbot come up at the end. It'd be nice if I would be able to start tasks instead of reboot. Also more through documentation of the plugin directories, the *.psd1 files I put there don't seem to be loaded when I specify them in ModuleManifestsToLoad.

Expected Behavior

new Parameter for StartupScript = "$botdir.poshbot\startup.ps1"

Current Behavior

null

devblackops commented 7 years ago

Thanks for the feedback @shotah

Can you provide more specific on the reboot? I haven't seen that a reboot is needed when creating the task.

I'll take a look at ModuleManifestToLoad to make sure that's working correctly.

shotah commented 7 years ago

Hopefully I cleaned out anything that is not meant to be public. :) Here is the CI script I currently use to spin it up from scratch. Currently I have it deploy to the CI runner because I have a runner defined just for Posh-bot. My goal will be to get Posh-bot pushing choco packages out to lists of hosts on demands assuming this all starts to run correctly. :) Thanks for your help on this. updated config Oct 3rd

# clean up of old bots:
get-ScheduledTask Posh-Bot | 
Stop-ScheduledTask -ErrorAction SilentlyContinue
get-ScheduledTask Posh-Bot | 
Unregister-ScheduledTask -Confirm:$false -ErrorAction SilentlyContinue

# installing pre-req's
choco install vault -y 
choco install rsat -y
Add-LocalGroupMember -name "administrators" -Member "svc_account" -ea 0 

# note this has allowclobber, we assume we know what these modules do and we will override with them.
$modules = @("psslack","PoshBot","poshbot.XKCD","poshbot.Giphy","poshbot-module")
ForEach($module in $modules) 
{
    Write-output "Testing to see if $module is installed."
    Import-module $module -ea 0
    if(!(get-module $module))
    { 
        Install-Module -Name $module -Repository PSGallery -Force -AllowClobber 
    }
}

$botdirectory = ($pwd.Path + "\.poshbot")
Remove-Item `
    -Path $botdirectory `
    -Force `
    -Recurse `
    -ErrorAction SilentlyContinue

$ConfigPath  = "$botdirectory\PoshBot.psd1"
$myBotConfig = New-PoshBotConfiguration
$myBotConfig.Name = 'Posh-Bot'
$myBotConfig.LogDirectory               = $botdirectory
$myBotConfig.ConfigurationDirectory     = $botdirectory
$myBotConfig.PluginDirectory            = $botdirectory
$myBotConfig.PluginRepository           = @("psmodules-local")
$myBotConfig.ModuleManifestsToLoad      = @("poshbot-module")
$myBotConfig.BotAdmins                  = @("chris")
$myBotConfig.CommandPrefix              = '!'
$myBotConfig.AlternateCommandPrefixSeperators = @(';')
$myBotConfig.AlternateCommandPrefixes   = 'poshbot'
$myBotConfig.LogLevel                   = 'Verbose'
$myBotConfig.CommandHistoryMaxLogSizeMB = 250
$myBotConfig.LogCommandHistory          = $true
$myBotConfig.MuteUnknownCommand         = $false
$myBotConfig.BackendConfiguration       = @{
    Name  = 'SlackBackend'
    Token = 'xoxb-*****-*****'
}
$myBotConfig.PluginConfiguration        = @{
    'poshbot-module' = @{
        secret = ($env:poshpw | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString)
        test = "Hello Chris! :fb_laugh:"
    }
}
Save-PoshBotConfiguration -InputObject $myBotConfig -Force -Path $ConfigPath

$creds = New-Object PSCredential ("svc_account",(ConvertTo-SecureString $env:poshpw -As -Fo))
$task  = New-PoshBotScheduledTask -Name 'Posh-Bot' -Path $ConfigPath -Credential $creds -Force
$task  | Start-ScheduledTask 

if((get-ScheduledTask Posh-Bot).state -ne "Running")
{
    Start-Process "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe" { start-sleep 15; restart-computer -force }
}
shotah commented 7 years ago

Error comes in when I add any module into the ModuleManifestsToLoad. Even anything like Poshbot.XKCD.

shotah commented 7 years ago

Sorry to ask, still working on this and I can share my updated code in a bit. How do you reference stored variables in the imported module? Say I stored the secret and now need my module to take advantage of that?

devblackops commented 7 years ago

If you're talking about a secret that was put into the bot configuration under the PluginConfiguration section, then you decorate a function parameter in your module with PoshBot.FromConfig()] That tells PoshBot to pull the value from the config and insert it as a named parameter when it executes your function.

config.psd1

### other config stuff
PluginConfiguration = @{
    MyModule = @{
        Credential = (Get-Credential -Username mycred)
    }
}
function Get-Foo {
    [PoshBot.FromConfig()]
    [cmdletbinding()]
    param(
        [parameter(mandatory)
        [pscredential]$Credential
    )
   ...
}

When you call the command from Slack, you don't need to specify the mandatory parameter. Since you decorated the parameter with [PoshBot.FromConfig()], PoshBot takes care of resolving it on your behalf.

In Slack

!get-foo

If you're talking about storing data between command executions (since they run as a job, nothing stateful is stored), you can use the Get/Set-PoshBotStatefulData public functions that Poshbot exposes. Those were added by @RamblingCookieMonster and allow you to store and retrieve private data between command executions. Internally they use Import/Export-CliXml so you can put any type of data in them.

Hope that helps!

shotah commented 7 years ago

Okay so this is where I am now. It doesn't seem to be filling in the test param.

CI Script to stand up the bot:

$myBotConfig.PluginConfiguration        = @{
    'poshbot-module' = @{
        secret = ($env:poshpw | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString)
        test = "Hello Chris! :fb_laugh: "
    }
}

Module function trying to call on the parameter I stored.

function Get-Foo {
    [PoshBot.FromConfig()]
    param(
        [parameter(mandatory)]
        [string]$test
    )

    Write-Output $test
}

Error I am getting: When I try !get-foo --test

Command Exception
Cannot find the type for custom attribute 'PoshBot.FromConfig'. Make sure that the assembly that contains this type is loaded.
devblackops commented 7 years ago

Ah yes. Sorry. Make sure you depend on PoshBot in your module manifest. You'll need that in order to use the [PoshBot.BotCommand()] or [PoshBot.FromConfig()] custom attributes.

Any I gave you the wrong location to put that attribute. You decorate the paramater with [PoshBot.FromConfig()]. The [PoshBot.BotCommand()] attributes is used at the function level alongside [cmdletbinding()].

Sorry for the confusion.

function Get-Foo {
    [cmdletbinding()]
    param(
        [PoshBot.FromConfig()]
        [parameter(mandatory)
        [pscredential]$Credential
    )
   ...
}
devblackops commented 7 years ago

This is only really documented in the New-PoshBotConfiguration help I think. This really needs to be a top level documentation item (among many others).

shotah commented 7 years ago

So I'm getting an error about the actual PoshBot module. So to nest it in the required modules I need to import it to our internal repo, but Nuget isn't willing to build it so I can do an publish on it.

nuget.exe : '' is not a valid version string.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:8355 char:19
+ ...   $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory  ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: ('' is not a valid version string.:String) [], Remote 
   Exception
    + FullyQualifiedErrorId : NativeCommandError

Full Json Error MSg

{
    "Exception":  {
                      "SerializedRemoteException":  null,
                      "SerializedRemoteInvocationInfo":  null,
                      "ErrorRecord":  {
                                          "Exception":  "System.Management.Automation.ParentContainsErrorRecordException: \u0027\u0027 is not a valid version string.",
                                          "TargetObject":  null,
                                          "CategoryInfo":  "NotSpecified: (:) [], ParentContainsErrorRecordException",
                                          "FullyQualifiedErrorId":  "RuntimeException",
                                          "ErrorDetails":  null,
                                          "InvocationInfo":  null,
                                          "ScriptStackTrace":  null,
                                          "PipelineIterationInfo":  ""
                                      },
                      "WasThrownFromThrowStatement":  false,
                      "Message":  "\u0027\u0027 is not a valid version string.",
                      "Data":  {

                               },
                      "InnerException":  null,
                      "TargetSite":  null,
                      "StackTrace":  null,
                      "HelpLink":  null,
                      "Source":  null,
                      "HResult":  -2146233087
                  },
    "TargetObject":  "\u0027\u0027 is not a valid version string.",
    "CategoryInfo":  {
                         "Category":  0,
                         "Activity":  "",
                         "Reason":  "RemoteException",
                         "TargetName":  "\u0027\u0027 is not a valid version string.",
                         "TargetType":  "String"
                     },
    "FullyQualifiedErrorId":  "NativeCommandError",
    "ErrorDetails":  null,
    "InvocationInfo":  {
                           "MyCommand":  {
                                             "Path":  "C:\\ProgramData\\chocolatey\\bin\\nuget.exe",
                                             "Extension":  ".exe",
                                             "Definition":  "C:\\ProgramData\\chocolatey\\bin\\nuget.exe",
                                             "Source":  "C:\\ProgramData\\chocolatey\\bin\\nuget.exe",
                                             "Version":  "3.5.0.0",
                                             "Visibility":  0,
                                             "OutputType":  "System.String",
                                             "Name":  "nuget.exe",
                                             "CommandType":  32,
                                             "ModuleName":  "",
                                             "Module":  null,
                                             "RemotingCapability":  1,
                                             "Parameters":  null,
                                             "ParameterSets":  null
                                         },
                           "BoundParameters":  {

                                               },
                           "UnboundArguments":  [

                                                ],
                           "ScriptLineNumber":  8355,
                           "OffsetInLine":  19,
                           "HistoryId":  -1,
                           "ScriptName":  "C:\\Program Files\\WindowsPowerShell\\Modules\\PowerShellGet\\1.0.0.1\\PSModule.psm1",
                           "Line":  "        $output = \u0026 $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot\r\n",
                           "PositionMessage":  "At C:\\Program Files\\WindowsPowerShell\\Modules\\PowerShellGet\\1.0.0.1\\PSModule.psm1:8355 char:19\r\n+ ...   $output = \u0026 $script:NuGetExePath pack $Nu
specPath -OutputDirectory  ...\r\n+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
                           "PSScriptRoot":  "C:\\Program Files\\WindowsPowerShell\\Modules\\PowerShellGet\\1.0.0.1",
                           "PSCommandPath":  "C:\\Program Files\\WindowsPowerShell\\Modules\\PowerShellGet\\1.0.0.1\\PSModule.psm1",
                           "InvocationName":  "\u0026",
                           "PipelineLength":  0,
                           "PipelinePosition":  0,
                           "ExpectingInput":  false,
                           "CommandOrigin":  1,
                           "DisplayScriptPosition":  null
                       },
    "ScriptStackTrace":  "at Publish-PSArtifactUtility, C:\\Program Files\\WindowsPowerShell\\Modules\\PowerShellGet\\1.0.0.1\\PSModule.psm1: line 8355\r\nat Publish-Module\u003cProcess\u003e, C:\\Program F
iles\\WindowsPowerShell\\Modules\\PowerShellGet\\1.0.0.1\\PSModule.psm1: line 1234\r\nat \u003cScriptBlock\u003e, .\\module-import-and-exp
ort.ps1: line 21",
    "PipelineIterationInfo":  [
                                  0,
                                  0
                              ],
    "writeErrorStream":  true,
    "PSMessageDetails":  null
}
shotah commented 7 years ago

@devblackops Any ideas why I get this error when trying to publish-module Poshbot to my internal Artiactory repo? Fyi, I also updated nuget to 4.3 and still got the above error.

devblackops commented 7 years ago

When you publish to Artifactory, are you publishing the built module or straight from the PoshBot\ subfolder in the repo? There is a psake task called Build which will create a usable module from the source files. building.md has more info on that. Also, since PoshBot has dependencies on the Configuration and PSSlack modules, you'll need to make sure those are published to Artifactory first.

shotah commented 7 years ago

@devblackops I have been able to import export Configuration and PSSlack just fine. It was PoshBot that won't export. So I basically just do an Install from PSGallery and then have PowerShell just publish into our internal repo.

Register-PSRepository `
    -Name $repo  `
    -SourceLocation  "http://$server/artifactory/api/nuget/$repo" `
    -PublishLocation "http://$server/artifactory/api/nuget/$repo" `
    -PackageManagementProvider nuget -ea SilentlyContinue 

$module = "PoshBot"
Update-module $module 
Import-module $module 
$mod = Get-Module $module
$mod | Publish-Module -Repository $repo -NuGetApiKey $chriskey -RequiredVersion 0.8.0

Errors

nuget.exe : '' is not a valid version string.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:8355 char:19
+ ...   $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory  ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: ('' is not a valid version string.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Publish-PSArtifactUtility : Failed to generate the compressed file for module 'Attempting to build package from 
'PoshBot.nuspec'.'.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:1227 char:17
+                 Publish-PSArtifactUtility -PSModuleInfo $moduleInfo `
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : FailedToCreateCompressedModule,Publish-PSArtifactUtility
devblackops commented 7 years ago

Odd. Tomorrow I'll try and publish PoshBot to an Artifactory instance.

shotah commented 7 years ago

@devblackops Technically it doesn't even get past the nuget.exe build. I also updated and removed the old PowerShellGet module off my box, in case that was the hangup.

Script     1.1.3.2    powershellget                       {Find-Command, Find-DscResource,...
shotah commented 7 years ago

@devblackops Anyluck? I tried from a fresh build from this repo and no luck either. How did you publish this to PSGallery?

devblackops commented 7 years ago

I was able to publish PoshBot to my Artifactory instance just fine. I already had the Configuration and PSSlack modules published.

These are the steps:

  1. Run build.ps1 -task build to compile the finished module in the \out\poshbot\ folder.
  2. Run Publish-Module -Path .\out\poshbot -Repository Artifactory -NuGetApiKey xxx
shotah commented 7 years ago

That worked! Never tried publishing the folder before. Publish-Module -path "$home\Documents\PoshBot\out\PoshBot\" -NuGetApiKey $chriskey