Skip to content

Commit 51f740d

Browse files
author
Deborah Barnard
committed
first commit
1 parent d7f8da0 commit 51f740d

13 files changed

+13962
-0
lines changed

.editorconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = tab
6+
indent_size = 2
7+
end_of_line = lf
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[package.json]
12+
indent_style = space
13+
indent_size = 2
14+
15+
[*.yml]
16+
indent_style = space
17+
indent_size = 2

.eslintrc.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module.exports = {
2+
root: true,
3+
4+
env: {
5+
browser: true,
6+
es6: true,
7+
node: true,
8+
},
9+
10+
parser: '@typescript-eslint/parser',
11+
parserOptions: {
12+
project: ['./tsconfig.json'],
13+
sourceType: 'module',
14+
extraFileExtensions: ['.json'],
15+
},
16+
ignorePatterns: [
17+
'.eslintrc.js',
18+
'**/*.js',
19+
'**/node_modules/**',
20+
'**/dist/**',
21+
],
22+
23+
overrides: [
24+
{
25+
files: ['package.json'],
26+
plugins: ['eslint-plugin-n8n-nodes-base'],
27+
extends: ['plugin:n8n-nodes-base/community'],
28+
rules: {
29+
'n8n-nodes-base/community-package-json-name-still-default': 'off',
30+
}
31+
},
32+
{
33+
files: ['./credentials/**/*.ts'],
34+
plugins: ['eslint-plugin-n8n-nodes-base'],
35+
extends: ['plugin:n8n-nodes-base/credentials'],
36+
rules: {
37+
'n8n-nodes-base/cred-class-field-documentation-url-missing': 'off',
38+
'n8n-nodes-base/cred-class-field-documentation-url-miscased': 'off',
39+
},
40+
},
41+
{
42+
files: ['./nodes/**/*.ts'],
43+
plugins: ['eslint-plugin-n8n-nodes-base'],
44+
extends: ['plugin:n8n-nodes-base/nodes'],
45+
rules: {
46+
'n8n-nodes-base/node-execute-block-missing-continue-on-fail': 'off',
47+
'n8n-nodes-base/node-resource-description-filename-against-convention': 'off',
48+
'n8n-nodes-base/node-param-fixed-collection-type-unsorted-items': 'off',
49+
'n8n-nodes-base/node-execute-block-operation-missing-singular-pairing': 'off',
50+
'n8n-nodes-base/node-execute-block-operation-missing-plural-pairing': 'off',
51+
},
52+
},
53+
],
54+
};

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
dist

.prettierrc.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module.exports = {
2+
/**
3+
* https://prettier.io/docs/en/options.html#semicolons
4+
*/
5+
semi: true,
6+
7+
/**
8+
* https://prettier.io/docs/en/options.html#trailing-commas
9+
*/
10+
trailingComma: 'all',
11+
12+
/**
13+
* https://prettier.io/docs/en/options.html#bracket-spacing
14+
*/
15+
bracketSpacing: true,
16+
17+
/**
18+
* https://prettier.io/docs/en/options.html#tabs
19+
*/
20+
useTabs: true,
21+
22+
/**
23+
* https://prettier.io/docs/en/options.html#tab-width
24+
*/
25+
tabWidth: 2,
26+
27+
/**
28+
* https://prettier.io/docs/en/options.html#arrow-function-parentheses
29+
*/
30+
arrowParens: 'always',
31+
32+
/**
33+
* https://prettier.io/docs/en/options.html#quotes
34+
*/
35+
singleQuote: true,
36+
37+
/**
38+
* https://prettier.io/docs/en/options.html#quote-props
39+
*/
40+
quoteProps: 'as-needed',
41+
42+
/**
43+
* https://prettier.io/docs/en/options.html#end-of-line
44+
*/
45+
endOfLine: 'lf',
46+
47+
/**
48+
* https://prettier.io/docs/en/options.html#print-width
49+
*/
50+
printWidth: 100,
51+
};

gulpfile.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const path = require('path');
2+
const { task, src, dest } = require('gulp');
3+
4+
task('build:icons', copyIcons);
5+
6+
function copyIcons() {
7+
const nodeSource = path.resolve('nodes', '**', '*.{png,svg}');
8+
const nodeDestination = path.resolve('dist', 'nodes');
9+
10+
src(nodeSource).pipe(dest(nodeDestination));
11+
12+
const credSource = path.resolve('credentials', '**', '*.{png,svg}');
13+
const credDestination = path.resolve('dist', 'credentials');
14+
15+
return src(credSource).pipe(dest(credDestination));
16+
}

index.js

Whitespace-only changes.

nodes/PowerShell/PowerShell.node.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"node": "n8n-nodes-base.PowerShell",
3+
"nodeVersion": "1.0",
4+
"codexVersion": "1.0",
5+
"categories": [
6+
"Development"
7+
],
8+
"resources": {
9+
"primaryDocumentation": [
10+
{
11+
"url": "https://github.com/StarfallProjects/n8n-nodes-powershell"
12+
}
13+
]
14+
}
15+
}

nodes/PowerShell/PowerShell.node.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { IExecuteFunctions } from 'n8n-core';
2+
import {
3+
INodeExecutionData,
4+
INodeType,
5+
INodeTypeDescription,
6+
NodeOperationError,
7+
} from 'n8n-workflow';
8+
9+
import { exec } from 'child_process';
10+
11+
export interface IExecReturnData {
12+
exitCode: number;
13+
error?: Error;
14+
stderr: string;
15+
stdout: string;
16+
}
17+
18+
/**
19+
* Promisifiy exec manually to also get the exit code
20+
*
21+
* @param {string} command
22+
* @returns {Promise<IExecReturnData>}
23+
*/
24+
function execPromise(command: string): Promise<IExecReturnData> {
25+
const returnData: IExecReturnData = {
26+
error: undefined,
27+
exitCode: 0,
28+
stderr: '',
29+
stdout: '',
30+
};
31+
32+
return new Promise((resolve, reject) => {
33+
exec(command, { 'shell': 'powershell.exe' }, (error, stdout, stderr) => {
34+
returnData.stdout = stdout.trim();
35+
returnData.stderr = stderr.trim();
36+
37+
if (error) {
38+
returnData.error = error;
39+
}
40+
41+
resolve(returnData);
42+
}).on('exit', (code) => {
43+
returnData.exitCode = code || 0;
44+
});
45+
});
46+
}
47+
48+
export class PowerShell implements INodeType {
49+
description: INodeTypeDescription = {
50+
displayName: 'PowerShell',
51+
name: 'PowerShell',
52+
icon: 'file:powershell.svg',
53+
group: [],
54+
version: 1,
55+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
56+
description: 'Run PowerShell commands from n8n',
57+
defaults: {
58+
name: 'PowerShell'
59+
},
60+
inputs: ['main'],
61+
outputs: ['main'],
62+
properties: [
63+
{
64+
displayName: 'Command',
65+
name: 'command',
66+
type: 'string',
67+
default: '',
68+
typeOptions: {
69+
rows: 10,
70+
},
71+
placeholder: 'Write-Output "Hello World"',
72+
description: 'The command to execute',
73+
},
74+
{
75+
displayName: 'Execute Once',
76+
name: 'executeOnce',
77+
type: 'boolean',
78+
default: true,
79+
description: 'Whether to execute only once (enabled) instead of once for each entry (disabled)',
80+
},
81+
],
82+
};
83+
84+
85+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
86+
let items = this.getInputData();
87+
let command: string;
88+
const executeOnce = this.getNodeParameter('executeOnce', 0) as boolean;
89+
90+
if (executeOnce === true) {
91+
items = [items[0]];
92+
}
93+
const returnItems: INodeExecutionData[] = [];
94+
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
95+
try {
96+
command = this.getNodeParameter('command', itemIndex) as string;
97+
98+
const { error, exitCode, stdout, stderr } = await execPromise(command);
99+
100+
if (error !== undefined) {
101+
throw new NodeOperationError(this.getNode(), error.message, { itemIndex });
102+
}
103+
104+
returnItems.push({
105+
json: {
106+
exitCode,
107+
stderr,
108+
stdout,
109+
},
110+
pairedItem: {
111+
item: itemIndex,
112+
},
113+
});
114+
} catch (error) {
115+
if (this.continueOnFail()) {
116+
returnItems.push({
117+
json: {
118+
error: error.message,
119+
},
120+
pairedItem: {
121+
item: itemIndex,
122+
},
123+
});
124+
continue;
125+
}
126+
throw error;
127+
}
128+
}
129+
130+
return this.prepareOutputData(returnItems);
131+
}
132+
133+
};

nodes/PowerShell/powershell.svg

Lines changed: 29 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)